Compare commits

...

43 Commits

Author SHA1 Message Date
notzippy
97ec142262 Merge pull request #117 from tike/master
fix import path trimming during main.go generation
2018-02-04 16:32:57 -08:00
tike
dfc873bc15 fix import path trimming during main.go generation
The importPathFromPath function invoked during `revel build`
in callchain Build -> ProcessSource ->  importPathFromPath
assumes that the vendor folder is in the app's root directory
when trimming import paths for inclusion into autogenerated
templates.

Consequently vendor detection fails if the vendor folder
is located at another hiher layer in the directory tree
and /prefix/path/to/vendor/ is not stripped from the
import path, leading to inclusion of invalid importpaths,
resulting in compilation error and build abortion.

This fix makes the vendor folder detection more flexible,
allowing for the vendor folder to be present at any higher
level in the directory hirachy.
2018-02-01 15:25:13 +01:00
notzippy
cca02dd5ff Merge pull request #116 from notzippy/log-update
Added check to ignore functions which have no body (external functions)
2018-01-30 09:47:56 -08:00
NotZippy
91f43bf94c Added check to ignore functions which have no body (external functions)
Added missing sort package
2018-01-30 09:23:21 -08:00
notzippy
0583fe7d32 Merge pull request #108 from rokeller/develop
Generate same value of AppVersion regardless of where revel is run
2018-01-29 21:28:08 -08:00
notzippy
6ca1d73b61 Merge pull request #112 from nathantchan/stable_controllers
Sort controllers so that builds are reproducible.
2018-01-29 21:27:18 -08:00
notzippy
4c87861642 Merge pull request #114 from vin01/master
Adding referrer policy security header
2018-01-29 21:26:33 -08:00
notzippy
a2d7517ca0 Merge pull request #115 from runner-mei/master
add support to map as a argument in the controller action
2018-01-29 21:25:49 -08:00
meifakun
8efaff19ce map as a argument in the controller action 2018-01-15 16:07:46 +08:00
vin01
ac056d17af Adding referrer policy security header
It will set a default strict `Referrer-Policy ``strict-origin-when-cross-origin`` that controls what referrer information shall be included with requests.
More: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy, https://scotthelme.co.uk/a-new-security-header-referrer-policy/
It can prevent issues like: https://robots.thoughtbot.com/is-your-site-leaking-password-reset-links
2018-01-06 14:05:20 +05:30
Nathan Chan
fc904827cd Make sorting compatible with go >= 1.6 2017-12-11 09:55:26 -08:00
Nathan Chan
c240b05369 Sort controllers so that builds are reproducible.
Ordering of controllers in routes.go and main.go is unstable in
successive runs of revel build.  This change will assure that the
ordering is stable.
2017-12-08 11:37:28 -08:00
notzippy
29e594435c Merge pull request #104 from notzippy/log-update
Prerelease items
2017-10-31 08:12:16 -07:00
Roger Keller
a2acbe32bf Make sure AppVersion is set without the -dirty suffix for non-dirty work trees regardless of where revel is run from. 2017-10-28 21:20:28 +02:00
NotZippy
29c6237caf Removed the catch all route, and added comment about security issue 2017-10-22 09:31:18 -07:00
NotZippy
2d4ccf289c Set line number to use left parenthesis not right 2017-10-07 21:41:23 -07:00
notzippy
f38fb6a15d Merge pull request #103 from notzippy/log-update
Updated skeleton to added critical.
2017-10-07 21:41:05 -07:00
NotZippy
637ccbd250 Updated skeleton to added critical.
modified db.import to support multiple packages
2017-10-07 21:39:13 -07:00
notzippy
2da4734499 Merge pull request #101 from notzippy/log-update
Vendor changes
2017-09-25 09:10:40 -07:00
NotZippy
aa9e0f8600 Added code to make vendoring work 2017-09-25 07:36:48 -07:00
notzippy
db4054233b Merge pull request #99 from Acidic9/master
Remove abort with 'revel new' on empty directory
2017-09-24 13:17:32 -07:00
Ari Seyhun
3907c6575e Clean code 2017-09-23 14:20:09 +09:30
notzippy
27e9fab270 Merge pull request #100 from notzippy/log-update
Logging error added more compile warnings
2017-09-21 10:50:28 -07:00
NotZippy
17e7d40d31 Fixed missing debug context parameter name
Added check to see if specfication was not exported
Added warnings if expected types did not match specification
2017-09-20 17:49:34 -07:00
Ari Seyhun
54ce8d3699 Remove abort with 'revel new' on empty directory
If you use 'revel new ...' on an empty directory, revel will abort complaining the directory exists.

With this commit, it will no longer abort if the directory is empty.
2017-09-16 15:24:37 +09:30
notzippy
8ab98db556 Merge pull request #98 from notzippy/log-update
Updated command to use new logging
2017-09-14 17:16:59 -07:00
NotZippy
baf5e9f848 Added check to see if parameter was a local object, if so parse it 2017-09-14 17:15:22 -07:00
NotZippy
9d57681ae6 Updated command to use new logging 2017-09-02 09:10:21 -07:00
notzippy
3f136726db Merge pull request #97 from notzippy/listener-fix
Changed listener to be a pointer receiver
2017-08-25 15:55:14 -07:00
NotZippy
c0a515facf Changed listener to be a pointer receiver so setting the channel to nil actually persists 2017-08-24 21:48:49 -07:00
notzippy
01494f75fb Merge pull request #96 from notzippy/autorun
Added mutex lock on Refresh, removed check for app existence
2017-08-07 20:55:21 -07:00
NotZippy
e6b34786bb Added mutex lock on Refresh, removed check for app existence 2017-08-07 16:56:19 -07:00
notzippy
79b2afb5e5 Merge pull request #95 from notzippy/autorun
Made develop mode autorun on start
2017-08-03 20:00:26 -07:00
NotZippy
5fcde12193 Moved watcher inside harness
Modified proxy so application is launched on startup
2017-07-28 13:27:28 -07:00
notzippy
ad68773b9e Merge pull request #91 from notzippy/server-engine-2
Server Engine 2
2017-07-24 12:49:34 -07:00
NotZippy
e5255cd373 Updated as requested 2017-07-06 15:31:43 -07:00
NotZippy
3cf6d5094e Changed skeleton back to original 2017-06-07 09:45:09 -07:00
NotZippy
efcd02de37 Modified harness to bootstrap using the go engine. Skeleton app updated to use new request code 2017-06-07 09:45:09 -07:00
notzippy
7eda33eb71 Merge pull request #93 from notzippy/cmd-fix
Fixed captialization
2017-05-31 20:25:56 -07:00
NotZippy
1c5fb4a6f8 Fixed captialization 2017-05-31 20:25:04 -07:00
Brenden Soares
a699dab33d Merge pull request #61 from krhubert/develop
Use config.http.addr and config.http.ssl for create baseURL local server
2017-05-30 21:46:51 -07:00
krhubert
0381636044 Typo in httpProto 2016-08-17 10:20:13 +02:00
krhubert
fb3980ce9d Use config.http.addr and config.http.ssl for create baseURL test server 2016-08-11 11:41:48 +02:00
13 changed files with 302 additions and 209 deletions

View File

@@ -58,11 +58,11 @@ func NewAppCmd(binPath string, port int) AppCmd {
// Start the app server, and wait until it is ready to serve requests. // Start the app server, and wait until it is ready to serve requests.
func (cmd AppCmd) Start() error { func (cmd AppCmd) Start() error {
listeningWriter := startupListeningWriter{os.Stdout, make(chan bool)} listeningWriter := &startupListeningWriter{os.Stdout, make(chan bool)}
cmd.Stdout = listeningWriter cmd.Stdout = listeningWriter
revel.TRACE.Println("Exec app:", cmd.Path, cmd.Args) revel.RevelLog.Debug("Exec app:", "path", cmd.Path, "args", cmd.Args)
if err := cmd.Cmd.Start(); err != nil { if err := cmd.Cmd.Start(); err != nil {
revel.ERROR.Fatalln("Error running:", err) revel.RevelLog.Fatal("Error running:", "error", err)
} }
select { select {
@@ -70,6 +70,7 @@ func (cmd AppCmd) Start() error {
return errors.New("revel/harness: app died") return errors.New("revel/harness: app died")
case <-time.After(30 * time.Second): case <-time.After(30 * time.Second):
revel.RevelLog.Debug("Killing revel server process did not respond after wait timeout", "processid", cmd.Process.Pid)
cmd.Kill() cmd.Kill()
return errors.New("revel/harness: app timed out") return errors.New("revel/harness: app timed out")
@@ -83,19 +84,19 @@ func (cmd AppCmd) Start() error {
// Run the app server inline. Never returns. // Run the app server inline. Never returns.
func (cmd AppCmd) Run() { func (cmd AppCmd) Run() {
revel.TRACE.Println("Exec app:", cmd.Path, cmd.Args) revel.RevelLog.Debug("Exec app:", "path", cmd.Path, "args", cmd.Args)
if err := cmd.Cmd.Run(); err != nil { if err := cmd.Cmd.Run(); err != nil {
revel.ERROR.Fatalln("Error running:", err) revel.RevelLog.Fatal("Error running:", "error", err)
} }
} }
// Kill terminates the app server if it's running. // Kill terminates the app server if it's running.
func (cmd AppCmd) Kill() { func (cmd AppCmd) Kill() {
if cmd.Cmd != nil && (cmd.ProcessState == nil || !cmd.ProcessState.Exited()) { if cmd.Cmd != nil && (cmd.ProcessState == nil || !cmd.ProcessState.Exited()) {
revel.TRACE.Println("Killing revel server pid", cmd.Process.Pid) revel.RevelLog.Debug("Killing revel server pid", "pid", cmd.Process.Pid)
err := cmd.Process.Kill() err := cmd.Process.Kill()
if err != nil { if err != nil {
revel.ERROR.Fatalln("Failed to kill revel server:", err) revel.RevelLog.Fatal("Failed to kill revel server:", "error", err)
} }
} }
} }
@@ -118,7 +119,7 @@ type startupListeningWriter struct {
notifyReady chan bool notifyReady chan bool
} }
func (w startupListeningWriter) Write(p []byte) (n int, err error) { func (w *startupListeningWriter) Write(p []byte) (n int, err error) {
if w.notifyReady != nil && bytes.Contains(p, []byte("Listening")) { if w.notifyReady != nil && bytes.Contains(p, []byte("Listening")) {
w.notifyReady <- true w.notifyReady <- true
w.notifyReady = nil w.notifyReady = nil

152
harness/build.go Executable file → Normal file
View File

@@ -17,12 +17,19 @@ import (
"strings" "strings"
"text/template" "text/template"
"time" "time"
"sort"
"github.com/revel/revel" "github.com/revel/revel"
) )
var importErrorPattern = regexp.MustCompile("cannot find package \"([^\"]+)\"") var importErrorPattern = regexp.MustCompile("cannot find package \"([^\"]+)\"")
type ByString []*TypeInfo
func (c ByString) Len() int { return len(c) }
func (c ByString) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c ByString) Less(i, j int) bool { return c[i].String() < c[j].String() }
// Build the app: // Build the app:
// 1. Generate the the main.go file. // 1. Generate the the main.go file.
// 2. Run the appropriate "go build" command. // 2. Run the appropriate "go build" command.
@@ -39,12 +46,16 @@ func Build(buildFlags ...string) (app *App, compileError *revel.Error) {
// Add the db.import to the import paths. // Add the db.import to the import paths.
if dbImportPath, found := revel.Config.String("db.import"); found { if dbImportPath, found := revel.Config.String("db.import"); found {
sourceInfo.InitImportPaths = append(sourceInfo.InitImportPaths, dbImportPath) sourceInfo.InitImportPaths = append(sourceInfo.InitImportPaths, strings.Split(dbImportPath, ",")...)
} }
// Sort controllers so that file generation is reproducible
controllers := sourceInfo.ControllerSpecs()
sort.Stable(ByString(controllers))
// Generate two source files. // Generate two source files.
templateArgs := map[string]interface{}{ templateArgs := map[string]interface{}{
"Controllers": sourceInfo.ControllerSpecs(), "Controllers": controllers,
"ValidationKeys": sourceInfo.ValidationKeys, "ValidationKeys": sourceInfo.ValidationKeys,
"ImportPaths": calcImportAliases(sourceInfo), "ImportPaths": calcImportAliases(sourceInfo),
"TestSuites": sourceInfo.TestSuites(), "TestSuites": sourceInfo.TestSuites(),
@@ -59,12 +70,46 @@ func Build(buildFlags ...string) (app *App, compileError *revel.Error) {
// It relies on the user having "go" installed. // It relies on the user having "go" installed.
goPath, err := exec.LookPath("go") goPath, err := exec.LookPath("go")
if err != nil { if err != nil {
revel.ERROR.Fatalf("Go executable not found in PATH.") revel.RevelLog.Fatalf("Go executable not found in PATH.")
}
// Detect if deps tool should be used (is there a vendor folder ?)
useVendor := revel.DirExists(filepath.Join(revel.BasePath, "vendor"))
basePath := revel.BasePath
for !useVendor {
basePath = filepath.Dir(basePath)
found := false
// Check to see if we are still in the GOPATH
for _, path := range filepath.SplitList(build.Default.GOPATH) {
if strings.HasPrefix(basePath, path) {
found = true
break
}
}
if !found {
break
} else {
useVendor = revel.DirExists(filepath.Join(basePath, "vendor"))
}
}
var depPath string
if useVendor {
revel.RevelLog.Info("Vendor folder detected, scanning for deps in path")
depPath, err = exec.LookPath("dep")
if err != nil {
// Do not halt build unless a new package needs to be imported
revel.RevelLog.Warn("Build: `dep` executable not found in PATH, but vendor folder detected." +
"Packages can only be added automatically to the vendor folder using the `dep` tool. " +
"You can install the `dep` tool by doing a `go get -u github.com/golang/dep/cmd/dep`")
}
} else {
revel.RevelLog.Info("No vendor folder detected, not using dependency manager to import files")
} }
pkg, err := build.Default.Import(revel.ImportPath, "", build.FindOnly) pkg, err := build.Default.Import(revel.ImportPath, "", build.FindOnly)
if err != nil { if err != nil {
revel.ERROR.Fatalln("Failure importing", revel.ImportPath) revel.RevelLog.Fatal("Failure importing", "path", revel.ImportPath)
} }
// Binary path is a combination of $GOBIN/revel.d directory, app's import path and its name. // Binary path is a combination of $GOBIN/revel.d directory, app's import path and its name.
@@ -87,13 +132,6 @@ func Build(buildFlags ...string) (app *App, compileError *revel.Error) {
versionLinkerFlags := fmt.Sprintf("-X %s/app.AppVersion=%s -X %s/app.BuildTime=%s", versionLinkerFlags := fmt.Sprintf("-X %s/app.AppVersion=%s -X %s/app.BuildTime=%s",
revel.ImportPath, appVersion, revel.ImportPath, buildTime) revel.ImportPath, appVersion, revel.ImportPath, buildTime)
// TODO remove version check for versionLinkerFlags after Revel becomes Go min version to go1.5
goVersion, err := strconv.ParseFloat(runtime.Version()[2:5], 64)
// runtime.Version() may return commit hash, we assume it is above 1.5
if goVersion < 1.5 && err == nil {
versionLinkerFlags = fmt.Sprintf("-X %s/app.AppVersion \"%s\" -X %s/app.BuildTime \"%s\"",
revel.ImportPath, appVersion, revel.ImportPath, buildTime)
}
flags := []string{ flags := []string{
"build", "build",
"-i", "-i",
@@ -109,42 +147,58 @@ func Build(buildFlags ...string) (app *App, compileError *revel.Error) {
flags = append(flags, path.Join(revel.ImportPath, "app", "tmp")) flags = append(flags, path.Join(revel.ImportPath, "app", "tmp"))
buildCmd := exec.Command(goPath, flags...) buildCmd := exec.Command(goPath, flags...)
revel.TRACE.Println("Exec:", buildCmd.Args) revel.RevelLog.Debug("Exec:", "args", buildCmd.Args)
output, err := buildCmd.CombinedOutput() output, err := buildCmd.CombinedOutput()
// If the build succeeded, we're done. // If the build succeeded, we're done.
if err == nil { if err == nil {
return NewApp(binName), nil return NewApp(binName), nil
} }
revel.ERROR.Println(string(output)) revel.RevelLog.Error(string(output))
// See if it was an import error that we can go get. // See if it was an import error that we can go get.
matches := importErrorPattern.FindStringSubmatch(string(output)) matches := importErrorPattern.FindAllStringSubmatch(string(output), -1)
if matches == nil { if matches == nil {
return nil, newCompileError(output) return nil, newCompileError(output)
} }
for _, match := range matches {
// Ensure we haven't already tried to go get it.
pkgName := match[1]
if _, alreadyTried := gotten[pkgName]; alreadyTried {
return nil, newCompileError(output)
}
gotten[pkgName] = struct{}{}
// Ensure we haven't already tried to go get it. // Execute "go get <pkg>"
pkgName := matches[1] // Or dep `dep ensure -add <pkg>` if it is there
if _, alreadyTried := gotten[pkgName]; alreadyTried { var getCmd *exec.Cmd
return nil, newCompileError(output) if useVendor {
} if depPath == "" {
gotten[pkgName] = struct{}{} revel.RevelLog.Error("Build: Vendor folder found, but the `dep` tool was not found, " +
"if you use a different vendoring (package management) tool please add the following packages by hand, " +
// Execute "go get <pkg>" "or install the `dep` tool into your gopath by doing a `go get -u github.com/golang/dep/cmd/dep`. " +
getCmd := exec.Command(goPath, "get", pkgName) "For more information and usage of the tool please see http://github.com/golang/dep")
revel.TRACE.Println("Exec:", getCmd.Args) for _, pkg := range matches {
getOutput, err := getCmd.CombinedOutput() revel.RevelLog.Error("Missing package", "package", pkg[1])
if err != nil { }
revel.ERROR.Println(string(getOutput)) }
return nil, newCompileError(output) getCmd = exec.Command(depPath, "ensure", "-add", pkgName)
} else {
getCmd = exec.Command(goPath, "get", pkgName)
}
revel.RevelLog.Debug("Exec:", "args", getCmd.Args)
getOutput, err := getCmd.CombinedOutput()
if err != nil {
revel.RevelLog.Error(string(getOutput))
return nil, newCompileError(output)
}
} }
// Success getting the import, attempt to build again. // Success getting the import, attempt to build again.
} }
// TODO remove this unreachable code and document it // TODO remove this unreachable code and document it
revel.ERROR.Fatalf("Not reachable") revel.RevelLog.Fatalf("Not reachable")
return nil, nil return nil, nil
} }
@@ -167,12 +221,12 @@ func getAppVersion() string {
if (err != nil && os.IsNotExist(err)) || !info.IsDir() { if (err != nil && os.IsNotExist(err)) || !info.IsDir() {
return "" return ""
} }
gitCmd := exec.Command(gitPath, "--git-dir="+gitDir, "describe", "--always", "--dirty") gitCmd := exec.Command(gitPath, "--git-dir="+gitDir, "--work-tree="+revel.BasePath, "describe", "--always", "--dirty")
revel.TRACE.Println("Exec:", gitCmd.Args) revel.RevelLog.Debug("Exec:", "args", gitCmd.Args)
output, err := gitCmd.Output() output, err := gitCmd.Output()
if err != nil { if err != nil {
revel.WARN.Println("Cannot determine git repository version:", err) revel.RevelLog.Warn("Cannot determine git repository version:", "error", err)
return "" return ""
} }
@@ -189,12 +243,12 @@ func cleanSource(dirs ...string) {
} }
func cleanDir(dir string) { func cleanDir(dir string) {
revel.INFO.Println("Cleaning dir " + dir) revel.RevelLog.Info("Cleaning dir " + dir)
tmpPath := filepath.Join(revel.AppPath, dir) tmpPath := filepath.Join(revel.AppPath, dir)
f, err := os.Open(tmpPath) f, err := os.Open(tmpPath)
if err != nil { if err != nil {
if !os.IsNotExist(err) { if !os.IsNotExist(err) {
revel.ERROR.Println("Failed to clean dir:", err) revel.RevelLog.Error("Failed to clean dir:", "error", err)
} }
} else { } else {
defer func() { defer func() {
@@ -204,20 +258,20 @@ func cleanDir(dir string) {
infos, err := f.Readdir(0) infos, err := f.Readdir(0)
if err != nil { if err != nil {
if !os.IsNotExist(err) { if !os.IsNotExist(err) {
revel.ERROR.Println("Failed to clean dir:", err) revel.RevelLog.Error("Failed to clean dir:", "error", err)
} }
} else { } else {
for _, info := range infos { for _, info := range infos {
path := filepath.Join(tmpPath, info.Name()) pathName := filepath.Join(tmpPath, info.Name())
if info.IsDir() { if info.IsDir() {
err := os.RemoveAll(path) err := os.RemoveAll(pathName)
if err != nil { if err != nil {
revel.ERROR.Println("Failed to remove dir:", err) revel.RevelLog.Error("Failed to remove dir:", "error", err)
} }
} else { } else {
err := os.Remove(path) err := os.Remove(pathName)
if err != nil { if err != nil {
revel.ERROR.Println("Failed to remove file:", err) revel.RevelLog.Error("Failed to remove file:", "error", err)
} }
} }
} }
@@ -237,20 +291,20 @@ func genSource(dir, filename, templateSource string, args map[string]interface{}
tmpPath := filepath.Join(revel.AppPath, dir) tmpPath := filepath.Join(revel.AppPath, dir)
err := os.Mkdir(tmpPath, 0777) err := os.Mkdir(tmpPath, 0777)
if err != nil && !os.IsExist(err) { if err != nil && !os.IsExist(err) {
revel.ERROR.Fatalf("Failed to make '%v' directory: %v", dir, err) revel.RevelLog.Fatalf("Failed to make '%v' directory: %v", dir, err)
} }
// Create the file // Create the file
file, err := os.Create(filepath.Join(tmpPath, filename)) file, err := os.Create(filepath.Join(tmpPath, filename))
if err != nil { if err != nil {
revel.ERROR.Fatalf("Failed to create file: %v", err) revel.RevelLog.Fatalf("Failed to create file: %v", err)
} }
defer func() { defer func() {
_ = file.Close() _ = file.Close()
}() }()
if _, err = file.WriteString(sourceCode); err != nil { if _, err = file.WriteString(sourceCode); err != nil {
revel.ERROR.Fatalf("Failed to write to file: %v", err) revel.RevelLog.Fatalf("Failed to write to file: %v", err)
} }
} }
@@ -287,7 +341,7 @@ func calcImportAliases(src *SourceInfo) map[string]string {
} }
func addAlias(aliases map[string]string, importPath, pkgName string) { func addAlias(aliases map[string]string, importPath, pkgName string) {
alias, ok := aliases[importPath] alias, ok := aliases[importPath]
if ok { if ok {
return return
} }
@@ -298,7 +352,7 @@ func addAlias(aliases map[string]string, importPath, pkgName string) {
func makePackageAlias(aliases map[string]string, pkgName string) string { func makePackageAlias(aliases map[string]string, pkgName string) string {
i := 0 i := 0
alias := pkgName alias := pkgName
for containsValue(aliases, alias) || alias=="revel" { for containsValue(aliases, alias) || alias == "revel" {
alias = fmt.Sprintf("%s%d", pkgName, i) alias = fmt.Sprintf("%s%d", pkgName, i)
i++ i++
} }
@@ -323,7 +377,7 @@ func newCompileError(output []byte) *revel.Error {
errorMatch = regexp.MustCompile(`(?m)^(.*?)\:(\d+)\:\s(.*?)$`).FindSubmatch(output) errorMatch = regexp.MustCompile(`(?m)^(.*?)\:(\d+)\:\s(.*?)$`).FindSubmatch(output)
if errorMatch == nil { if errorMatch == nil {
revel.ERROR.Println("Failed to parse build errors:\n", string(output)) revel.RevelLog.Error("Failed to parse build errors", "error", string(output))
return &revel.Error{ return &revel.Error{
SourceType: "Go code", SourceType: "Go code",
Title: "Go Compilation Error", Title: "Go Compilation Error",
@@ -333,7 +387,7 @@ func newCompileError(output []byte) *revel.Error {
errorMatch = append(errorMatch, errorMatch[3]) errorMatch = append(errorMatch, errorMatch[3])
revel.ERROR.Println("Build errors:\n", string(output)) revel.RevelLog.Error("Build errors", "errors", string(output))
} }
// Read the source for the offending file. // Read the source for the offending file.
@@ -360,7 +414,7 @@ func newCompileError(output []byte) *revel.Error {
fileStr, err := revel.ReadLines(absFilename) fileStr, err := revel.ReadLines(absFilename)
if err != nil { if err != nil {
compileError.MetaError = absFilename + ": " + err.Error() compileError.MetaError = absFilename + ": " + err.Error()
revel.ERROR.Println(compileError.MetaError) revel.RevelLog.Error(compileError.MetaError)
return compileError return compileError
} }
@@ -393,7 +447,7 @@ var (
func main() { func main() {
flag.Parse() flag.Parse()
revel.Init(*runMode, *importPath, *srcPath) revel.Init(*runMode, *importPath, *srcPath)
revel.INFO.Println("Running revel server") revel.AppLog.Info("Running revel server")
{{range $i, $c := .Controllers}} {{range $i, $c := .Controllers}}
revel.RegisterController((*{{index $.ImportPaths .ImportPath}}.{{.StructName}})(nil), revel.RegisterController((*{{index $.ImportPaths .ImportPath}}.{{.StructName}})(nil),
[]*revel.MethodType{ []*revel.MethodType{

View File

@@ -29,10 +29,10 @@ import (
"sync/atomic" "sync/atomic"
"github.com/revel/revel" "github.com/revel/revel"
"sync"
) )
var ( var (
watcher *revel.Watcher
doNotWatch = []string{"tmp", "views", "routes"} doNotWatch = []string{"tmp", "views", "routes"}
lastRequestHadError int32 lastRequestHadError int32
@@ -45,12 +45,16 @@ type Harness struct {
serverHost string serverHost string
port int port int
proxy *httputil.ReverseProxy proxy *httputil.ReverseProxy
watcher *revel.Watcher
mutex *sync.Mutex
} }
func renderError(w http.ResponseWriter, r *http.Request, err error) { func renderError(iw http.ResponseWriter, ir *http.Request, err error) {
req, resp := revel.NewRequest(r), revel.NewResponse(w) context := revel.NewGoContext(nil)
c := revel.NewController(req, resp) context.Request.SetRequest(ir)
c.RenderError(err).Apply(req, resp) context.Response.SetResponse(iw)
c := revel.NewController(context)
c.RenderError(err).Apply(c.Request, c.Response)
} }
// ServeHTTP handles all requests. // ServeHTTP handles all requests.
@@ -63,12 +67,17 @@ func (h *Harness) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Flush any change events and rebuild app if necessary. // Flush any change events and rebuild app if necessary.
// Render an error page if the rebuild / restart failed. // Render an error page if the rebuild / restart failed.
err := watcher.Notify() err := h.watcher.Notify()
if err != nil { if err != nil {
// In a thread safe manner update the flag so that a request for
// /favicon.ico does not trigger a rebuild
atomic.CompareAndSwapInt32(&lastRequestHadError, 0, 1) atomic.CompareAndSwapInt32(&lastRequestHadError, 0, 1)
renderError(w, r, err) renderError(w, r, err)
return return
} }
// In a thread safe manner update the flag so that a request for
// /favicon.ico is allowed
atomic.CompareAndSwapInt32(&lastRequestHadError, 1, 0) atomic.CompareAndSwapInt32(&lastRequestHadError, 1, 0)
// Reverse proxy the request. // Reverse proxy the request.
@@ -88,7 +97,7 @@ func NewHarness() *Harness {
revel.MainTemplateLoader = revel.NewTemplateLoader( revel.MainTemplateLoader = revel.NewTemplateLoader(
[]string{filepath.Join(revel.RevelPath, "templates")}) []string{filepath.Join(revel.RevelPath, "templates")})
if err := revel.MainTemplateLoader.Refresh(); err != nil { if err := revel.MainTemplateLoader.Refresh(); err != nil {
revel.ERROR.Println(err) revel.RevelLog.Error("Template loader error", "error", err)
} }
addr := revel.HTTPAddr addr := revel.HTTPAddr
@@ -109,27 +118,32 @@ func NewHarness() *Harness {
serverURL, _ := url.ParseRequestURI(fmt.Sprintf(scheme+"://%s:%d", addr, port)) serverURL, _ := url.ParseRequestURI(fmt.Sprintf(scheme+"://%s:%d", addr, port))
harness := &Harness{ serverHarness := &Harness{
port: port, port: port,
serverHost: serverURL.String()[len(scheme+"://"):], serverHost: serverURL.String()[len(scheme+"://"):],
proxy: httputil.NewSingleHostReverseProxy(serverURL), proxy: httputil.NewSingleHostReverseProxy(serverURL),
mutex: &sync.Mutex{},
} }
if revel.HTTPSsl { if revel.HTTPSsl {
harness.proxy.Transport = &http.Transport{ serverHarness.proxy.Transport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
} }
} }
return harness return serverHarness
} }
// Refresh method rebuilds the Revel application and run it on the given port. // Refresh method rebuilds the Revel application and run it on the given port.
func (h *Harness) Refresh() (err *revel.Error) { func (h *Harness) Refresh() (err *revel.Error) {
// Allow only one thread to rebuild the process
h.mutex.Lock()
defer h.mutex.Unlock()
if h.app != nil { if h.app != nil {
h.app.Kill() h.app.Kill()
} }
revel.TRACE.Println("Rebuild") revel.RevelLog.Debug("Rebuild Called")
h.app, err = Build() h.app, err = Build()
if err != nil { if err != nil {
return return
@@ -153,7 +167,7 @@ func (h *Harness) WatchDir(info os.FileInfo) bool {
} }
// WatchFile method returns true given filename HasSuffix of ".go" // WatchFile method returns true given filename HasSuffix of ".go"
// otheriwse false // otheriwse false - implements revel.DiscerningListener
func (h *Harness) WatchFile(filename string) bool { func (h *Harness) WatchFile(filename string) bool {
return strings.HasSuffix(filename, ".go") return strings.HasSuffix(filename, ".go")
} }
@@ -167,12 +181,13 @@ func (h *Harness) Run() {
paths = append(paths, gopaths...) paths = append(paths, gopaths...)
} }
paths = append(paths, revel.CodePaths...) paths = append(paths, revel.CodePaths...)
watcher = revel.NewWatcher() h.watcher = revel.NewWatcher()
watcher.Listen(h, paths...) h.watcher.Listen(h, paths...)
h.watcher.Notify()
go func() { go func() {
addr := fmt.Sprintf("%s:%d", revel.HTTPAddr, revel.HTTPPort) addr := fmt.Sprintf("%s:%d", revel.HTTPAddr, revel.HTTPPort)
revel.INFO.Printf("Listening on %s", addr) revel.RevelLog.Infof("Listening on %s", addr)
var err error var err error
if revel.HTTPSsl { if revel.HTTPSsl {
@@ -185,7 +200,7 @@ func (h *Harness) Run() {
err = http.ListenAndServe(addr, h) err = http.ListenAndServe(addr, h)
} }
if err != nil { if err != nil {
revel.ERROR.Fatalln("Failed to start reverse proxy:", err) revel.RevelLog.Error("Failed to start reverse proxy:", "error", err)
} }
}() }()
@@ -203,13 +218,13 @@ func (h *Harness) Run() {
func getFreePort() (port int) { func getFreePort() (port int) {
conn, err := net.Listen("tcp", ":0") conn, err := net.Listen("tcp", ":0")
if err != nil { if err != nil {
revel.ERROR.Fatal(err) revel.RevelLog.Fatal("Unable to fetch a freee port address", "error", err)
} }
port = conn.Addr().(*net.TCPAddr).Port port = conn.Addr().(*net.TCPAddr).Port
err = conn.Close() err = conn.Close()
if err != nil { if err != nil {
revel.ERROR.Fatal(err) revel.RevelLog.Fatal("Unable to close port", "error", err)
} }
return port return port
} }
@@ -231,7 +246,7 @@ func proxyWebsocket(w http.ResponseWriter, r *http.Request, host string) {
} }
if err != nil { if err != nil {
http.Error(w, "Error contacting backend server.", 500) http.Error(w, "Error contacting backend server.", 500)
revel.ERROR.Printf("Error dialing websocket backend %s: %v", host, err) revel.RevelLog.Error("Error dialing websocket backend ", "host", host, "error", err)
return return
} }
hj, ok := w.(http.Hijacker) hj, ok := w.(http.Hijacker)
@@ -241,21 +256,21 @@ func proxyWebsocket(w http.ResponseWriter, r *http.Request, host string) {
} }
nc, _, err := hj.Hijack() nc, _, err := hj.Hijack()
if err != nil { if err != nil {
revel.ERROR.Printf("Hijack error: %v", err) revel.RevelLog.Error("Hijack error", "error", err)
return return
} }
defer func() { defer func() {
if err = nc.Close(); err != nil { if err = nc.Close(); err != nil {
revel.ERROR.Println(err) revel.RevelLog.Error("Connection close error", "error", err)
} }
if err = d.Close(); err != nil { if err = d.Close(); err != nil {
revel.ERROR.Println(err) revel.RevelLog.Error("Dial close error", "error", err)
} }
}() }()
err = r.Write(d) err = r.Write(d)
if err != nil { if err != nil {
revel.ERROR.Printf("Error copying request to target: %v", err) revel.RevelLog.Error("Error copying request to target", "error", err)
return return
} }

View File

@@ -13,12 +13,14 @@ import (
"go/parser" "go/parser"
"go/scanner" "go/scanner"
"go/token" "go/token"
"log"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"unicode"
"github.com/revel/revel" "github.com/revel/revel"
"log"
) )
// SourceInfo is the top-level struct containing all extracted information // SourceInfo is the top-level struct containing all extracted information
@@ -98,14 +100,14 @@ func ProcessSource(roots []string) (*SourceInfo, *revel.Error) {
for _, root := range roots { for _, root := range roots {
rootImportPath := importPathFromPath(root) rootImportPath := importPathFromPath(root)
if rootImportPath == "" { if rootImportPath == "" {
revel.WARN.Println("Skipping code path", root) revel.RevelLog.Warn("Skipping empty code path", "path", root)
continue continue
} }
// Start walking the directory tree. // Start walking the directory tree.
_ = revel.Walk(root, func(path string, info os.FileInfo, err error) error { _ = revel.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
log.Println("Error scanning app source:", err) revel.RevelLog.Error("Error scanning app source:", "error", err)
return nil return nil
} }
@@ -149,7 +151,7 @@ func ProcessSource(roots []string) (*SourceInfo, *revel.Error) {
// This is exception, err alredy checked above. Here just a print // This is exception, err alredy checked above. Here just a print
ast.Print(nil, err) ast.Print(nil, err)
log.Fatalf("Failed to parse dir: %s", err) revel.RevelLog.Fatal("Failed to parse dir", "error", err)
} }
// Skip "main" packages. // Skip "main" packages.
@@ -160,9 +162,21 @@ func ProcessSource(roots []string) (*SourceInfo, *revel.Error) {
return nil return nil
} }
// Ignore packages that end with _test
for i := range pkgs {
if len(i) > 6 {
if string(i[len(i)-5:]) == "_test" {
delete(pkgs, i)
}
}
}
// There should be only one package in this directory. // There should be only one package in this directory.
if len(pkgs) > 1 { if len(pkgs) > 1 {
log.Println("Most unexpected! Multiple packages in a single directory:", pkgs) for i := range pkgs {
println("Found package ", i)
}
revel.RevelLog.Error("Most unexpected! Multiple packages in a single directory:", "packages", pkgs)
} }
var pkg *ast.Package var pkg *ast.Package
@@ -187,7 +201,7 @@ func appendSourceInfo(srcInfo1, srcInfo2 *SourceInfo) *SourceInfo {
srcInfo1.InitImportPaths = append(srcInfo1.InitImportPaths, srcInfo2.InitImportPaths...) srcInfo1.InitImportPaths = append(srcInfo1.InitImportPaths, srcInfo2.InitImportPaths...)
for k, v := range srcInfo2.ValidationKeys { for k, v := range srcInfo2.ValidationKeys {
if _, ok := srcInfo1.ValidationKeys[k]; ok { if _, ok := srcInfo1.ValidationKeys[k]; ok {
log.Println("Key conflict when scanning validation calls:", k) revel.RevelLog.Warn("Key conflict when scanning validation calls:", "key", k)
continue continue
} }
srcInfo1.ValidationKeys[k] = v srcInfo1.ValidationKeys[k] = v
@@ -209,8 +223,8 @@ func processPackage(fset *token.FileSet, pkgImportPath, pkgPath string, pkg *ast
) )
// For each source file in the package... // For each source file in the package...
log.Println("Exaiming files in path", pkgPath)
for _, file := range pkg.Files { for _, file := range pkg.Files {
// Imports maps the package key to the full import path. // Imports maps the package key to the full import path.
// e.g. import "sample/app/models" => "models": "sample/app/models" // e.g. import "sample/app/models" => "models": "sample/app/models"
imports := map[string]string{} imports := map[string]string{}
@@ -227,8 +241,8 @@ func processPackage(fset *token.FileSet, pkgImportPath, pkgPath string, pkg *ast
structSpecs = appendStruct(structSpecs, pkgImportPath, pkg, decl, imports, fset) structSpecs = appendStruct(structSpecs, pkgImportPath, pkg, decl, imports, fset)
} }
// If this is a func... // If this is a func... (ignore nil for external (non-Go) function)
if funcDecl, ok := decl.(*ast.FuncDecl); ok { if funcDecl, ok := decl.(*ast.FuncDecl); ok && funcDecl.Body != nil {
// Scan it for validation calls // Scan it for validation calls
lineKeys := getValidationKeys(fset, funcDecl, imports) lineKeys := getValidationKeys(fset, funcDecl, imports)
if len(lineKeys) > 0 { if len(lineKeys) > 0 {
@@ -305,7 +319,7 @@ func addImports(imports map[string]string, decl ast.Decl, srcDir string) {
// We expect this to happen for apps using reverse routing (since we // We expect this to happen for apps using reverse routing (since we
// have not yet generated the routes). Don't log that. // have not yet generated the routes). Don't log that.
if !strings.HasSuffix(fullPath, "/app/routes") { if !strings.HasSuffix(fullPath, "/app/routes") {
revel.TRACE.Println("Could not find import:", fullPath) revel.RevelLog.Debug("Could not find import:", "path", fullPath)
} }
continue continue
} }
@@ -324,6 +338,7 @@ func appendStruct(specs []*TypeInfo, pkgImportPath string, pkg *ast.Package, dec
if !found { if !found {
return specs return specs
} }
structType := spec.Type.(*ast.StructType) structType := spec.Type.(*ast.StructType)
// At this point we know it's a type declaration for a struct. // At this point we know it's a type declaration for a struct.
@@ -383,7 +398,7 @@ func appendStruct(specs []*TypeInfo, pkgImportPath string, pkg *ast.Package, dec
} else { } else {
var ok bool var ok bool
if importPath, ok = imports[pkgName]; !ok { if importPath, ok = imports[pkgName]; !ok {
log.Print("Failed to find import path for ", pkgName, ".", typeName) revel.RevelLog.Error("Failed to find import path for ", "package", pkgName, "type", typeName)
continue continue
} }
} }
@@ -442,13 +457,16 @@ func appendAction(fset *token.FileSet, mm methodMap, decl ast.Decl, pkgImportPat
var importPath string var importPath string
typeExpr := NewTypeExpr(pkgName, field.Type) typeExpr := NewTypeExpr(pkgName, field.Type)
if !typeExpr.Valid { if !typeExpr.Valid {
log.Printf("Didn't understand argument '%s' of action %s. Ignoring.\n", name, getFuncName(funcDecl)) revel.RevelLog.Warnf("Didn't understand argument '%s' of action %s. Ignoring.", name, getFuncName(funcDecl))
return // We didn't understand one of the args. Ignore this action. return // We didn't understand one of the args. Ignore this action.
} }
if typeExpr.PkgName != "" { // Local object
if typeExpr.PkgName == pkgName {
importPath = pkgImportPath
} else if typeExpr.PkgName != "" {
var ok bool var ok bool
if importPath, ok = imports[typeExpr.PkgName]; !ok { if importPath, ok = imports[typeExpr.PkgName]; !ok {
log.Println("Failed to find import for arg of type:", typeExpr.TypeName("")) revel.RevelLog.Errorf("Failed to find import for arg of type: %s , %s", typeExpr.PkgName, typeExpr.TypeName(""))
} }
} }
method.Args = append(method.Args, &MethodArg{ method.Args = append(method.Args, &MethodArg{
@@ -482,7 +500,7 @@ func appendAction(fset *token.FileSet, mm methodMap, decl ast.Decl, pkgImportPat
} }
// Add this call's args to the renderArgs. // Add this call's args to the renderArgs.
pos := fset.Position(callExpr.Rparen) pos := fset.Position(callExpr.Lparen)
methodCall := &methodCall{ methodCall := &methodCall{
Line: pos.Line, Line: pos.Line,
Names: []string{}, Names: []string{},
@@ -634,7 +652,7 @@ func getStructTypeDecl(decl ast.Decl, fset *token.FileSet) (spec *ast.TypeSpec,
} }
if len(genDecl.Specs) == 0 { if len(genDecl.Specs) == 0 {
revel.WARN.Printf("Surprising: %s:%d Decl contains no specifications", fset.Position(decl.Pos()).Filename, fset.Position(decl.Pos()).Line) revel.RevelLog.Warnf("Surprising: %s:%d Decl contains no specifications", fset.Position(decl.Pos()).Filename, fset.Position(decl.Pos()).Line)
return return
} }
@@ -647,7 +665,7 @@ func getStructTypeDecl(decl ast.Decl, fset *token.FileSet) (spec *ast.TypeSpec,
// TypesThatEmbed returns all types that (directly or indirectly) embed the // TypesThatEmbed returns all types that (directly or indirectly) embed the
// target type, which must be a fully qualified type name, // target type, which must be a fully qualified type name,
// e.g. "github.com/revel/revel.Controller" // e.g. "github.com/revel/revel.Controller"
func (s *SourceInfo) TypesThatEmbed(targetType string) (filtered []*TypeInfo) { func (s *SourceInfo) TypesThatEmbed(targetType, packageFilter string) (filtered []*TypeInfo) {
// Do a search in the "embedded type graph", starting with the target type. // Do a search in the "embedded type graph", starting with the target type.
var ( var (
nodeQueue = []string{targetType} nodeQueue = []string{targetType}
@@ -679,6 +697,37 @@ func (s *SourceInfo) TypesThatEmbed(targetType string) (filtered []*TypeInfo) {
} }
} }
} }
// Strip out any specifications that contain a lower case
for exit := false; !exit; exit = true {
for i, filteredItem := range filtered {
if unicode.IsLower([]rune(filteredItem.StructName)[0]) {
revel.RevelLog.Debug("Skipping adding spec for unexported type",
"type", filteredItem.StructName,
"package", filteredItem.ImportPath)
filtered = append(filtered[:i], filtered[i+1:]...)
exit = false
break
}
}
}
// Check for any missed types that where from expected packages
for _, spec := range s.StructSpecs {
if spec.PackageName == packageFilter {
found := false
for _, filteredItem := range filtered {
if filteredItem.StructName == spec.StructName {
found = true
break
}
}
if !found {
revel.RevelLog.Warn("Type found in package: "+packageFilter+
", but did not embed from: "+filepath.Base(targetType),
"name", spec.StructName, "path", spec.ImportPath)
}
}
}
return return
} }
@@ -686,7 +735,7 @@ func (s *SourceInfo) TypesThatEmbed(targetType string) (filtered []*TypeInfo) {
// `revel.Controller` // `revel.Controller`
func (s *SourceInfo) ControllerSpecs() []*TypeInfo { func (s *SourceInfo) ControllerSpecs() []*TypeInfo {
if s.controllerSpecs == nil { if s.controllerSpecs == nil {
s.controllerSpecs = s.TypesThatEmbed(revel.RevelImportPath + ".Controller") s.controllerSpecs = s.TypesThatEmbed(revel.RevelImportPath+".Controller", "controllers")
} }
return s.controllerSpecs return s.controllerSpecs
} }
@@ -695,7 +744,7 @@ func (s *SourceInfo) ControllerSpecs() []*TypeInfo {
// `testing.TestSuite` // `testing.TestSuite`
func (s *SourceInfo) TestSuites() []*TypeInfo { func (s *SourceInfo) TestSuites() []*TypeInfo {
if s.testSuites == nil { if s.testSuites == nil {
s.testSuites = s.TypesThatEmbed(revel.RevelImportPath + "/testing.TestSuite") s.testSuites = s.TypesThatEmbed(revel.RevelImportPath+"/testing.TestSuite", "testsuite")
} }
return s.testSuites return s.testSuites
} }
@@ -735,11 +784,18 @@ func NewTypeExpr(pkgName string, expr ast.Expr) TypeExpr {
case *ast.ArrayType: case *ast.ArrayType:
e := NewTypeExpr(pkgName, t.Elt) e := NewTypeExpr(pkgName, t.Elt)
return TypeExpr{"[]" + e.Expr, e.PkgName, e.pkgIndex + 2, e.Valid} return TypeExpr{"[]" + e.Expr, e.PkgName, e.pkgIndex + 2, e.Valid}
case *ast.MapType:
if identKey, ok := t.Key.(*ast.Ident); ok && IsBuiltinType(identKey.Name) {
e := NewTypeExpr(pkgName, t.Value)
return TypeExpr{"map[" + identKey.Name + "]" + e.Expr, e.PkgName, e.pkgIndex + len("map["+identKey.Name+"]"), e.Valid}
}
revel.RevelLog.Error("Failed to generate name for field. Make sure the field name is valid.")
case *ast.Ellipsis: case *ast.Ellipsis:
e := NewTypeExpr(pkgName, t.Elt) e := NewTypeExpr(pkgName, t.Elt)
return TypeExpr{"[]" + e.Expr, e.PkgName, e.pkgIndex + 2, e.Valid} return TypeExpr{"[]" + e.Expr, e.PkgName, e.pkgIndex + 2, e.Valid}
default: default:
log.Println("Failed to generate name for field. Make sure the field name is valid.") revel.RevelLog.Error("Failed to generate name for field. Make sure the field name is valid.", "package", pkgName, "expresion",expr)
} }
return TypeExpr{Valid: false} return TypeExpr{Valid: false}
} }
@@ -774,9 +830,8 @@ func IsBuiltinType(name string) bool {
} }
func importPathFromPath(root string) string { func importPathFromPath(root string) string {
vendoringPath := revel.BasePath + "/vendor/" if vendorIdx := strings.Index(root, "/vendor/"); vendorIdx != -1 {
if strings.HasPrefix(root, vendoringPath) { return filepath.ToSlash(root[vendorIdx+8:])
return filepath.ToSlash(root[len(vendoringPath):])
} }
for _, gopath := range filepath.SplitList(build.Default.GOPATH) { for _, gopath := range filepath.SplitList(build.Default.GOPATH) {
srcPath := filepath.Join(gopath, "src") srcPath := filepath.Join(gopath, "src")
@@ -787,10 +842,10 @@ func importPathFromPath(root string) string {
srcPath := filepath.Join(build.Default.GOROOT, "src", "pkg") srcPath := filepath.Join(build.Default.GOROOT, "src", "pkg")
if strings.HasPrefix(root, srcPath) { if strings.HasPrefix(root, srcPath) {
revel.WARN.Println("Code path should be in GOPATH, but is in GOROOT:", root) revel.RevelLog.Warn("Code path should be in GOPATH, but is in GOROOT:", "path", root)
return filepath.ToSlash(root[len(srcPath)+1:]) return filepath.ToSlash(root[len(srcPath)+1:])
} }
revel.ERROR.Println("Unexpected! Code path is not in GOPATH:", root) revel.RevelLog.Error("Unexpected! Code path is not in GOPATH:", "path", root)
return "" return ""
} }

View File

@@ -8,8 +8,6 @@ import (
"go/ast" "go/ast"
"go/parser" "go/parser"
"go/token" "go/token"
"io/ioutil"
"log"
"reflect" "reflect"
"strings" "strings"
"testing" "testing"
@@ -96,18 +94,20 @@ func TestGetValidationKeys(t *testing.T) {
} }
var TypeExprs = map[string]TypeExpr{ var TypeExprs = map[string]TypeExpr{
"int": {"int", "", 0, true}, "int": {"int", "", 0, true},
"*int": {"*int", "", 1, true}, "*int": {"*int", "", 1, true},
"[]int": {"[]int", "", 2, true}, "[]int": {"[]int", "", 2, true},
"...int": {"[]int", "", 2, true}, "...int": {"[]int", "", 2, true},
"[]*int": {"[]*int", "", 3, true}, "[]*int": {"[]*int", "", 3, true},
"...*int": {"[]*int", "", 3, true}, "...*int": {"[]*int", "", 3, true},
"MyType": {"MyType", "pkg", 0, true}, "MyType": {"MyType", "pkg", 0, true},
"*MyType": {"*MyType", "pkg", 1, true}, "*MyType": {"*MyType", "pkg", 1, true},
"[]MyType": {"[]MyType", "pkg", 2, true}, "[]MyType": {"[]MyType", "pkg", 2, true},
"...MyType": {"[]MyType", "pkg", 2, true}, "...MyType": {"[]MyType", "pkg", 2, true},
"[]*MyType": {"[]*MyType", "pkg", 3, true}, "[]*MyType": {"[]*MyType", "pkg", 3, true},
"...*MyType": {"[]*MyType", "pkg", 3, true}, "...*MyType": {"[]*MyType", "pkg", 3, true},
"map[int]MyType": {"map[int]MyType", "pkg", 8, true},
"map[int]*MyType": {"map[int]*MyType", "pkg", 9, true},
} }
func TestTypeExpr(t *testing.T) { func TestTypeExpr(t *testing.T) {
@@ -183,7 +183,7 @@ NEXT_TEST:
func BenchmarkProcessBookingSource(b *testing.B) { func BenchmarkProcessBookingSource(b *testing.B) {
revel.Init("", "github.com/revel/examples/booking", "") revel.Init("", "github.com/revel/examples/booking", "")
revel.TRACE = log.New(ioutil.Discard, "", 0) revel.GetRootLogHandler().Disable()
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {

View File

@@ -60,11 +60,11 @@ func buildApp(args []string) {
} }
if err := os.RemoveAll(destPath); err != nil && !os.IsNotExist(err) { if err := os.RemoveAll(destPath); err != nil && !os.IsNotExist(err) {
revel.ERROR.Fatalln(err) revel.RevelLog.Fatal("Remove all error","error", err)
} }
if err := os.MkdirAll(destPath, 0777); err != nil { if err := os.MkdirAll(destPath, 0777); err != nil {
revel.ERROR.Fatalln(err) revel.RevelLog.Fatal("makedir error","error",err)
} }
app, reverr := harness.Build() app, reverr := harness.Build()
@@ -101,7 +101,7 @@ func buildApp(args []string) {
} }
modulePath, err := revel.ResolveImportPath(moduleImportPath) modulePath, err := revel.ResolveImportPath(moduleImportPath)
if err != nil { if err != nil {
revel.ERROR.Fatalln("Failed to load module %s: %s", key[len("module."):], err) revel.RevelLog.Fatalf("Failed to load module %s: %s", key[len("module."):], err)
} }
modulePaths[moduleImportPath] = modulePath modulePaths[moduleImportPath] = modulePath
} }

View File

@@ -8,7 +8,6 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"go/build" "go/build"
"log"
"math/rand" "math/rand"
"os" "os"
"os/exec" "os/exec"
@@ -67,8 +66,6 @@ func newApp(args []string) {
errorf("Too many arguments provided.\nRun 'revel help new' for usage.\n") errorf("Too many arguments provided.\nRun 'revel help new' for usage.\n")
} }
revel.ERROR.SetFlags(log.LstdFlags)
// checking and setting go paths // checking and setting go paths
initGoPaths() initGoPaths()
@@ -129,7 +126,7 @@ func initGoPaths() {
} }
if len(srcRoot) == 0 { if len(srcRoot) == 0 {
revel.ERROR.Fatalln("Abort: could not create a Revel application outside of GOPATH.") revel.RevelLog.Fatal("Abort: could not create a Revel application outside of GOPATH.")
} }
// set go src path // set go src path
@@ -148,8 +145,10 @@ func setApplicationPath(args []string) {
importPath) importPath)
} }
appPath = filepath.Join(srcRoot, filepath.FromSlash(importPath))
_, err = build.Import(importPath, "", build.FindOnly) _, err = build.Import(importPath, "", build.FindOnly)
if err == nil { if err == nil && !empty(appPath) {
errorf("Abort: Import path %s already exists.\n", importPath) errorf("Abort: Import path %s already exists.\n", importPath)
} }
@@ -158,7 +157,6 @@ func setApplicationPath(args []string) {
errorf("Abort: Could not find Revel source code: %s\n", err) errorf("Abort: Could not find Revel source code: %s\n", err)
} }
appPath = filepath.Join(srcRoot, filepath.FromSlash(importPath))
appName = filepath.Base(appPath) appName = filepath.Base(appPath)
basePath = filepath.ToSlash(filepath.Dir(importPath)) basePath = filepath.ToSlash(filepath.Dir(importPath))

View File

@@ -53,7 +53,7 @@ func packageApp(args []string) {
// Remove the archive if it already exists. // Remove the archive if it already exists.
destFile := filepath.Base(revel.BasePath) + ".tar.gz" destFile := filepath.Base(revel.BasePath) + ".tar.gz"
if err := os.Remove(destFile); err != nil && !os.IsNotExist(err) { if err := os.Remove(destFile); err != nil && !os.IsNotExist(err) {
revel.ERROR.Fatal(err) revel.RevelLog.Fatal("Unable to remove target file","error",err,"file",destFile)
} }
// Collect stuff in a temp directory. // Collect stuff in a temp directory.

View File

@@ -51,7 +51,7 @@ func parseRunArgs(args []string) *RunArgs {
} }
switch len(args) { switch len(args) {
case 3: case 3:
// Possibile combinations // Possible combinations
// revel run [import-path] [run-mode] [port] // revel run [import-path] [run-mode] [port]
port, err := strconv.Atoi(args[2]) port, err := strconv.Atoi(args[2])
if err != nil { if err != nil {
@@ -61,7 +61,7 @@ func parseRunArgs(args []string) *RunArgs {
inputArgs.Mode = args[1] inputArgs.Mode = args[1]
inputArgs.Port = port inputArgs.Port = port
case 2: case 2:
// Possibile combinations // Possible combinations
// 1. revel run [import-path] [run-mode] // 1. revel run [import-path] [run-mode]
// 2. revel run [import-path] [port] // 2. revel run [import-path] [port]
// 3. revel run [run-mode] [port] // 3. revel run [run-mode] [port]
@@ -85,11 +85,16 @@ func parseRunArgs(args []string) *RunArgs {
inputArgs.Port = port inputArgs.Port = port
} }
case 1: case 1:
// Possibile combinations // Possible combinations
// 1. revel run [import-path] // 1. revel run [import-path]
// 2. revel run [port] // 2. revel run [port]
// 3. revel run [run-mode] // 3. revel run [run-mode]
if _, err := build.Import(args[0], "", build.FindOnly); err == nil { _, err := build.Import(args[0], "", build.FindOnly)
if err != nil {
revel.RevelLog.Warn("Unable to run using an import path, assuming import path is working directory %s %s", "Argument", args[0], "error", err.Error())
}
println("Trying to build with", args[0], err)
if err == nil {
// 1st arg is the import path // 1st arg is the import path
inputArgs.ImportPath = args[0] inputArgs.ImportPath = args[0]
} else if port, err := strconv.Atoi(args[0]); err == nil { } else if port, err := strconv.Atoi(args[0]); err == nil {
@@ -116,18 +121,18 @@ func runApp(args []string) {
runArgs.Port = revel.HTTPPort runArgs.Port = revel.HTTPPort
} }
revel.INFO.Printf("Running %s (%s) in %s mode\n", revel.AppName, revel.ImportPath, runArgs.Mode) revel.RevelLog.Infof("Running %s (%s) in %s mode\n", revel.AppName, revel.ImportPath, runArgs.Mode)
revel.TRACE.Println("Base path:", revel.BasePath) revel.RevelLog.Debug("Base path:", "path", revel.BasePath)
// If the app is run in "watched" mode, use the harness to run it. // If the app is run in "watched" mode, use the harness to run it.
if revel.Config.BoolDefault("watch", true) && revel.Config.BoolDefault("watch.code", true) { if revel.Config.BoolDefault("watch", true) && revel.Config.BoolDefault("watch.code", true) {
revel.TRACE.Println("Running in watched mode.") revel.RevelLog.Debug("Running in watched mode.")
revel.HTTPPort = runArgs.Port revel.HTTPPort = runArgs.Port
harness.NewHarness().Run() // Never returns. harness.NewHarness().Run() // Never returns.
} }
// Else, just build and run the app. // Else, just build and run the app.
revel.TRACE.Println("Running in live build mode.") revel.RevelLog.Debug("Running in live build mode.")
app, err := harness.Build() app, err := harness.Build()
if err != nil { if err != nil {
errorf("Failed to build app: %s", err) errorf("Failed to build app: %s", err)

View File

@@ -29,8 +29,7 @@ func init() {
revel.ActionInvoker, // Invoke the action. revel.ActionInvoker, // Invoke the action.
} }
// Register startup functions with OnAppStart
// register startup functions with OnAppStart
// revel.DevMode and revel.RunMode only work inside of OnAppStart. See Example Startup Script // revel.DevMode and revel.RunMode only work inside of OnAppStart. See Example Startup Script
// ( order dependent ) // ( order dependent )
// revel.OnAppStart(ExampleStartupScript) // revel.OnAppStart(ExampleStartupScript)
@@ -39,13 +38,13 @@ func init() {
} }
// HeaderFilter adds common security headers // HeaderFilter adds common security headers
// TODO turn this into revel.HeaderFilter // There is a full implementation of a CSRF filter in
// should probably also have a filter for CSRF // https://github.com/revel/modules/tree/master/csrf
// not sure if it can go in the same filter or not
var HeaderFilter = func(c *revel.Controller, fc []revel.Filter) { var HeaderFilter = func(c *revel.Controller, fc []revel.Filter) {
c.Response.Out.Header().Add("X-Frame-Options", "SAMEORIGIN") c.Response.Out.Header().Add("X-Frame-Options", "SAMEORIGIN")
c.Response.Out.Header().Add("X-XSS-Protection", "1; mode=block") c.Response.Out.Header().Add("X-XSS-Protection", "1; mode=block")
c.Response.Out.Header().Add("X-Content-Type-Options", "nosniff") c.Response.Out.Header().Add("X-Content-Type-Options", "nosniff")
c.Response.Out.Header().Add("Referrer-Policy", "strict-origin-when-cross-origin")
fc[0](c, fc[1:]) // Execute the next filter stage. fc[0](c, fc[1:]) // Execute the next filter stage.
} }

View File

@@ -84,15 +84,6 @@ format.datetime = 2006-01-02 15:04
results.chunked = false results.chunked = false
# Prefixes for each log message line.
# User can override these prefix values within any section
# For e.g: [dev], [prod], etc
log.trace.prefix = "TRACE "
log.info.prefix = "INFO "
log.warn.prefix = "WARN "
log.error.prefix = "ERROR "
# The default language of this application. # The default language of this application.
i18n.default_language = en i18n.default_language = en
@@ -104,7 +95,7 @@ i18n.default_language = en
# Module to serve static content such as CSS, JavaScript and Media files # Module to serve static content such as CSS, JavaScript and Media files
# Allows Routes like this: # Allows Routes like this:
# `Static.ServeModule("modulename","public")` # `Static.ServeModule("modulename","public")`
module.static=github.com/revel/modules/static module.static = github.com/revel/modules/static
@@ -179,37 +170,14 @@ module.testrunner = github.com/revel/modules/testrunner
# Log to Os's standard error output. Default value. # Log to Os's standard error output. Default value.
# "relative/path/to/log" # "relative/path/to/log"
# Log to file. # Log to file.
log.trace.output = off log.all.filter.module.app = stdout # Log all loggers for the application to the stdout
log.info.output = stderr log.error.nfilter.module.app = stderr # Everything else that logs an error to stderr
log.warn.output = stderr log.crit.output = stderr # Everything that logs something as critical goes to this
log.error.output = stderr
# Revel log flags. Possible flags defined by the Go `log` package. Go log is
# "Bits OR'ed together to control what's printed
# See:
# https://golang.org/pkg/log/#pkg-constants
# Values:
# "0"
# Just log the message, turn off the flags.
# "3"
# log.LstdFlags (log.Ldate|log.Ltime)
# "19"
# log.Ldate|log.Ltime|log.Lshortfile
# "23"
# log.Ldate|log.Ltime|log.Lmicroseconds|log.Lshortfile
log.trace.flags = 19
log.info.flags = 19
log.warn.flags = 19
log.error.flags = 19
# Revel request access log # Revel request access log
# Access log line format: # Access log line format:
# RequestStartTime ClientIP ResponseStatus RequestLatency HTTPMethod URLPath # INFO 21:53:55 static server-engine.go:169: Request Stats ip=127.0.0.1 path=/public/vendors/datatables.net-buttons/js/buttons.html5.min.js method=GET start=2017/08/31 21:53:55 status=200 duration_seconds=0.0002583 section=requestlog
# Sample format: log.request.output = stdout
# 2016/05/25 17:46:37.112 127.0.0.1 200 270.157µs GET /
log.request.output = stderr
@@ -229,30 +197,11 @@ watch = false
module.testrunner = module.testrunner =
log.trace.output = off log.warn.output = log/%(app.name)-warn.json # Log all warn messages to file
log.info.output = off log.error.output = log/%(app.name)-error.json # Log all errors to file
log.warn.output = log/%(app.name)s.log log.crit.output = log/%(app.name)-critical.json # Log all critical to file
log.error.output = log/%(app.name)s.log
# Revel log flags. Possible flags defined by the Go `log` package, # Revel request access log (json format)
# please refer https://golang.org/pkg/log/#pkg-constants
# Go log is "Bits or'ed together to control what's printed"
# Examples:
# 0 => just log the message, turn off the flags
# 3 => log.LstdFlags (log.Ldate|log.Ltime)
# 19 => log.Ldate|log.Ltime|log.Lshortfile
# 23 => log.Ldate|log.Ltime|log.Lmicroseconds|log.Lshortfile
log.trace.flags = 3
log.info.flags = 3
log.warn.flags = 3
log.error.flags = 3
# Revel request access log
# Access log line format:
# RequestStartTime ClientIP ResponseStatus RequestLatency HTTPMethod URLPath
# Sample format:
# 2016/05/25 17:46:37.112 127.0.0.1 200 270.157µs GET /
# Example: # Example:
# log.request.output = %(app.name)s-request.log # log.request.output = %(app.name)s-request.json
log.request.output = off log.request.output = log/%(app.name)s-requests.json

View File

@@ -15,5 +15,12 @@ GET /favicon.ico 404
# Map static resources from the /app/public folder to the /public path # Map static resources from the /app/public folder to the /public path
GET /public/*filepath Static.Serve("public") GET /public/*filepath Static.Serve("public")
# Catch all # Catch all, this will route any request into the controller path
* /:controller/:action :controller.:action #
# **** WARNING ****
# Enabling this exposes any controller and function to the web.
# ** This is a serious security issue if used online **
#
# For rapid development uncomment the following to add new controller.action endpoints
# without having to add them to the routes table.
# * /:controller/:action :controller.:action

View File

@@ -97,8 +97,18 @@ func testApp(args []string) {
defer cmd.Kill() defer cmd.Kill()
revel.INFO.Printf("Testing %s (%s) in %s mode\n", revel.AppName, revel.ImportPath, mode) revel.INFO.Printf("Testing %s (%s) in %s mode\n", revel.AppName, revel.ImportPath, mode)
var httpAddr = revel.HTTPAddr
if httpAddr == "" {
httpAddr = "127.0.0.1"
}
var httpProto = "http"
if revel.HTTPSsl {
httpProto = "https"
}
// Get a list of tests // Get a list of tests
var baseURL = fmt.Sprintf("http://127.0.0.1:%d", revel.HTTPPort) var baseURL = fmt.Sprintf("%s://%s:%d", httpProto, httpAddr, revel.HTTPPort)
testSuites, _ := getTestsList(baseURL) testSuites, _ := getTestsList(baseURL)
// If a specific TestSuite[.Method] is specified, only run that suite/test // If a specific TestSuite[.Method] is specified, only run that suite/test