Compare commits

...

43 Commits

Author SHA1 Message Date
NotZippy
e1776bda3c Rollback a change that was committed by mistake to develop branch 2017-04-26 21:04:12 -07:00
notzippy
d68b27ae81 Merge pull request #86 from tw4452852/version
fix version check against devel
2017-04-21 08:55:01 -07:00
Brenden Soares
ce84b78204 Merge pull request #85 from revel/app.conf-cleanup-1
Adding consistent values and example formatting
2017-04-15 18:57:56 -07:00
Tw
19ca52182d fix version check against devel
Signed-off-by: Tw <tw19881113@gmail.com>
2017-04-10 22:31:37 +08:00
Brenden Soares
bf30aab381 Adding consistent values and example formatting 2017-04-07 12:05:14 -07:00
notzippy
bd4663b651 Merge pull request #84 from revel/app.conf-cleanup-1
App.conf cleanup 1
2017-04-07 12:05:08 -07:00
Brenden Soares
b81860de5f Remove unneeded quotes 2017-04-07 11:34:44 -07:00
NotZippy
d2b1730439 Makes it so harness can bootstrap using the new GoRequest / response wrappers 2017-04-04 17:17:23 -07:00
Brenden Soares
95d6366c0d Merge pull request #79 from revel/develop
v0.14.1
2017-03-24 21:19:22 -07:00
Brenden Soares
0f47be728a Merge pull request #78 from revel/issue77
Fixes issue #77 (regression bug when running `revel run appname`)
2017-03-24 21:17:39 -07:00
Brenden Soares
fb1f8c2706 Fixes issue #77 (regression bug when running revel run appname) 2017-03-24 20:41:17 -07:00
Brenden Soares
da79330cfb Merge pull request #76 from revel/develop
v0.14.0
2017-03-24 10:50:43 -07:00
Brenden Soares
6ec49296c9 Merge branch 'master' into develop 2017-03-24 10:38:36 -07:00
Shawn Catanzarite
0ec369fd48 Merge pull request #75 from shawncatz/cookie-secure-doc
update doc for cookie.secure to match new defaults and add addiitonal info
2017-03-20 15:04:26 -07:00
Shawn Catanzarite
5eac8fae04 change up wording 2017-03-20 14:59:20 -07:00
Shawn Catanzarite
3dcee9651d update doc for cookie.secure to match new defaults and add addiitonal info
see #1141
2017-03-20 14:45:51 -07:00
notzippy
6573696992 Merge pull request #72 from notzippy/sample-to-example
Found the issue with os...
2017-03-10 02:35:17 -08:00
NotZippy
a4888fa407 Found the issue with os... 2017-03-10 02:33:27 -08:00
notzippy
8e4203838a Merge pull request #71 from notzippy/sample-to-example
Changed samples to example to match repository
2017-03-09 16:45:24 -08:00
notzippy
e0aa1901b8 Merge pull request #69 from pedromorgan/pedro
Tidy up skeleton
2017-03-09 16:43:46 -08:00
Pedro Morgan
f6c6c931d3 fix onAppStart docs 2017-03-10 00:06:46 +00:00
NotZippy
8dac9acf77 Changed samples to example to match repository 2017-03-09 16:01:04 -08:00
notzippy
e634cbfc7d Merge pull request #68 from Fyb3roptik/develop
Added some example code to show that DevMode and RunMode only work fr…
2017-03-09 13:28:47 -08:00
Pedro Morgan
adcebf9aca Correct bootstrap error class 2017-03-05 01:50:46 +00:00
Pedro Morgan
7b90dfa83e Tidy up skeleton 2017-03-05 00:20:51 +00:00
Nick Wallace
d865cfce90 Added some example code to show that DevMode and RunMode only work from within OnAppStart
Hoping this helps someone else as it took me a while to figure it out. I was wanting to run DEV only code on init.
2016-11-18 13:29:06 -06:00
Brenden Soares
52400dbc3d Merge pull request #66 from Warashi/improve/support-binary-vendoring
supporting binary vendoring
2016-10-12 23:58:29 -07:00
sawada_shinnosuke
d8c5c0732f supporting binary vendoring 2016-08-29 11:03:20 +09:00
Jeevanandam M
62fc677f3a Merge pull request #60 from revel/ldflags-fix
ldflags issue commit, read more...
2016-07-21 17:24:26 -07:00
Jeevanandam M
0e6d8d56a2 ldflags issue commit, read more...
This commit is address 1.7 release. RC3 is already out there. It may lead to merge conflict while merging develop branch. Since enhancements are done.
2016-07-21 17:22:15 -07:00
Jeevanandam M
86e9258a8f Merge pull request #58 from revel/move-skeleton-to-cmd
skeleton moved successfully to cmd repo
2016-06-28 18:54:58 -07:00
Jeevanandam M
faf7e698f3 Merge pull request #57 from revel/app-version-buildtime
Streamlined app version ad buildtime for revel app
2016-06-28 18:54:33 -07:00
Jeevanandam M
54ef57e56d Done #52 skeleton moved successfully to cmd repo 2016-06-25 20:09:38 -07:00
Jeevanandam M
612de1d3a4 #51 - Streamlined app version ad buildtime for revel app 2016-06-25 19:04:40 -07:00
Jeevanandam M
28c0df2ff3 Merge pull request #56 from revel/revel-run-cmd-robust
Revel run cmd become more robust
2016-06-24 15:02:23 -07:00
Jeevanandam M
4b46dbb1a7 revel/revel#389 run cmd become more robust 2016-06-18 12:06:12 -07:00
Jeevanandam M
c18d43d25e Merge pull request #55 from sergeylanzman/master
fix -X import.name=value
2016-06-17 15:32:54 -07:00
Sergey Lanzman
ab1e84cf41 Streamline Revel AppVersion and BuildTime and fix -X import.name=value 2016-06-18 01:28:24 +03:00
Jeevanandam M
a5c8a8da09 revel/revel#1057 code improvements docs, errcheck, cyclo, etc 2016-06-17 14:34:22 -07:00
Jeevanandam M
5a57eaa743 revel/revel#1057 code improvements 2016-06-08 19:32:13 -07:00
Jeevanandam M
514b078c3d revel/revel#1057 addressing golint ALL_CAPS 2016-06-08 12:09:48 -07:00
Jeevanandam M
e485de7e9c #46 cross platform support 2016-06-07 00:16:51 -07:00
Jeevanandam M
4b9e74e1ea revel/revel#1064 windows filepath fix 2016-06-06 15:36:16 -07:00
37 changed files with 1105 additions and 269 deletions

3
.gitignore vendored Normal file
View File

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

View File

@@ -1,14 +1,19 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package harness
import (
"bytes"
"errors"
"fmt"
"github.com/revel/revel"
"io"
"os"
"os/exec"
"time"
"github.com/revel/revel"
)
// App contains the configuration for running a Revel app. (Not for the app itself)
@@ -19,11 +24,12 @@ type App struct {
cmd AppCmd // The last cmd returned.
}
// NewApp returns app instance with binary path in it
func NewApp(binPath string) *App {
return &App{BinaryPath: binPath}
}
// Return a command to run the app server using the current configuration.
// Cmd returns a command to run the app server using the current configuration.
func (a *App) Cmd() AppCmd {
a.cmd = NewAppCmd(a.BinaryPath, a.Port)
return a.cmd
@@ -40,6 +46,7 @@ type AppCmd struct {
*exec.Cmd
}
// NewAppCmd returns the AppCmd with parameters initialized for running app
func NewAppCmd(binPath string, port int) AppCmd {
cmd := exec.Command(binPath,
fmt.Sprintf("-port=%d", port),
@@ -69,6 +76,8 @@ func (cmd AppCmd) Start() error {
case <-listeningWriter.notifyReady:
return nil
}
// TODO remove this unreachable code and document it
panic("Impossible")
}
@@ -80,7 +89,7 @@ func (cmd AppCmd) Run() {
}
}
// Terminate the app server if it's running.
// Kill terminates the app server if it's running.
func (cmd AppCmd) Kill() {
if cmd.Cmd != nil && (cmd.ProcessState == nil || !cmd.ProcessState.Exited()) {
revel.TRACE.Println("Killing revel server pid", cmd.Process.Pid)
@@ -95,7 +104,7 @@ func (cmd AppCmd) Kill() {
func (cmd AppCmd) waitChan() <-chan struct{} {
ch := make(chan struct{}, 1)
go func() {
cmd.Wait()
_ = cmd.Wait()
ch <- struct{}{}
}()
return ch

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package harness
import (
@@ -12,6 +16,7 @@ import (
"strconv"
"strings"
"text/template"
"time"
"github.com/revel/revel"
)
@@ -44,8 +49,8 @@ func Build(buildFlags ...string) (app *App, compileError *revel.Error) {
"ImportPaths": calcImportAliases(sourceInfo),
"TestSuites": sourceInfo.TestSuites(),
}
genSource("tmp", "main.go", MAIN, templateArgs)
genSource("routes", "routes.go", ROUTES, templateArgs)
genSource("tmp", "main.go", RevelMainTemplate, templateArgs)
genSource("routes", "routes.go", RevelRoutesTemplate, templateArgs)
// Read build config.
buildTags := revel.Config.StringDefault("build.tags", "")
@@ -63,7 +68,7 @@ func Build(buildFlags ...string) (app *App, compileError *revel.Error) {
}
// Binary path is a combination of $GOBIN/revel.d directory, app's import path and its name.
binName := path.Join(pkg.BinDir, "revel.d", revel.ImportPath, path.Base(revel.BasePath))
binName := filepath.Join(pkg.BinDir, "revel.d", revel.ImportPath, filepath.Base(revel.BasePath))
// Change binary path for Windows build
goos := runtime.GOOS
@@ -77,7 +82,18 @@ func Build(buildFlags ...string) (app *App, compileError *revel.Error) {
gotten := make(map[string]struct{})
for {
appVersion := getAppVersion()
versionLinkerFlags := fmt.Sprintf("-X %s/app.APP_VERSION \"%s\"", revel.ImportPath, appVersion)
buildTime := time.Now().UTC().Format(time.RFC3339)
versionLinkerFlags := fmt.Sprintf("-X %s/app.AppVersion=%s -X %s/app.BuildTime=%s",
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{
"build",
"-i",
@@ -88,7 +104,8 @@ func Build(buildFlags ...string) (app *App, compileError *revel.Error) {
// Add in build flags
flags = append(flags, buildFlags...)
// The main path
// This is Go main path
// Note: It's not applicable for filepath.* usage
flags = append(flags, path.Join(revel.ImportPath, "app", "tmp"))
buildCmd := exec.Command(goPath, flags...)
@@ -125,6 +142,8 @@ func Build(buildFlags ...string) (app *App, compileError *revel.Error) {
// Success getting the import, attempt to build again.
}
// TODO remove this unreachable code and document it
revel.ERROR.Fatalf("Not reachable")
return nil, nil
}
@@ -143,7 +162,7 @@ func getAppVersion() string {
// Check for the git binary
if gitPath, err := exec.LookPath("git"); err == nil {
// Check for the .git directory
gitDir := path.Join(revel.BasePath, ".git")
gitDir := filepath.Join(revel.BasePath, ".git")
info, err := os.Stat(gitDir)
if (err != nil && os.IsNotExist(err)) || !info.IsDir() {
return ""
@@ -171,14 +190,17 @@ func cleanSource(dirs ...string) {
func cleanDir(dir string) {
revel.INFO.Println("Cleaning dir " + dir)
tmpPath := path.Join(revel.AppPath, dir)
tmpPath := filepath.Join(revel.AppPath, dir)
f, err := os.Open(tmpPath)
if err != nil {
if !os.IsNotExist(err) {
revel.ERROR.Println("Failed to clean dir:", err)
}
} else {
defer f.Close()
defer func() {
_ = f.Close()
}()
infos, err := f.Readdir(0)
if err != nil {
if !os.IsNotExist(err) {
@@ -186,7 +208,7 @@ func cleanDir(dir string) {
}
} else {
for _, info := range infos {
path := path.Join(tmpPath, info.Name())
path := filepath.Join(tmpPath, info.Name())
if info.IsDir() {
err := os.RemoveAll(path)
if err != nil {
@@ -212,20 +234,22 @@ func genSource(dir, filename, templateSource string, args map[string]interface{}
// Create a fresh dir.
cleanSource(dir)
tmpPath := path.Join(revel.AppPath, dir)
tmpPath := filepath.Join(revel.AppPath, dir)
err := os.Mkdir(tmpPath, 0777)
if err != nil && !os.IsExist(err) {
revel.ERROR.Fatalf("Failed to make '%v' directory: %v", dir, err)
}
// Create the file
file, err := os.Create(path.Join(tmpPath, filename))
defer file.Close()
file, err := os.Create(filepath.Join(tmpPath, filename))
if err != nil {
revel.ERROR.Fatalf("Failed to create file: %v", err)
}
_, err = file.WriteString(sourceCode)
if err != nil {
defer func() {
_ = file.Close()
}()
if _, err = file.WriteString(sourceCode); err != nil {
revel.ERROR.Fatalf("Failed to write to file: %v", err)
}
}
@@ -263,7 +287,7 @@ func calcImportAliases(src *SourceInfo) map[string]string {
}
func addAlias(aliases map[string]string, importPath, pkgName string) {
alias, ok := aliases[importPath]
alias, ok := aliases[importPath]
if ok {
return
}
@@ -274,7 +298,7 @@ func addAlias(aliases map[string]string, importPath, pkgName string) {
func makePackageAlias(aliases map[string]string, pkgName string) string {
i := 0
alias := pkgName
for containsValue(aliases, alias) {
for containsValue(aliases, alias) || alias=="revel" {
alias = fmt.Sprintf("%s%d", pkgName, i)
i++
}
@@ -344,7 +368,8 @@ func newCompileError(output []byte) *revel.Error {
return compileError
}
const MAIN = `// GENERATED CODE - DO NOT EDIT
// RevelMainTemplate template for app/tmp/main.go
const RevelMainTemplate = `// GENERATED CODE - DO NOT EDIT
package main
import (
@@ -398,7 +423,9 @@ func main() {
revel.Run(*port)
}
`
const ROUTES = `// GENERATED CODE - DO NOT EDIT
// RevelRoutesTemplate template for app/conf/routes
const RevelRoutesTemplate = `// GENERATED CODE - DO NOT EDIT
package routes
import "github.com/revel/revel"
@@ -414,7 +441,7 @@ func (_ t{{$c.StructName}}) {{.Name}}({{range .Args}}
args := make(map[string]string)
{{range .Args}}
revel.Unbind(args, "{{.Name}}", {{.Name}}){{end}}
return revel.MainRouter.Reverse("{{$c.StructName}}.{{.Name}}", args).Url
return revel.MainRouter.Reverse("{{$c.StructName}}.{{.Name}}", args).URL
}
{{end}}
{{end}}

View File

@@ -1,13 +1,16 @@
// The Harness for a Revel program.
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
// Package harness for a Revel Framework.
//
// It has a couple responsibilities:
// It has a following responsibilities:
// 1. Parse the user program, generating a main.go file that registers
// controller classes and starts the user's server.
// 2. Build and run the user program. Show compile errors.
// 3. Monitor the user source and re-build / restart the program when necessary.
//
// Source files are generated in the app/tmp directory.
package harness
import (
@@ -84,12 +87,14 @@ func NewHarness() *Harness {
// Prefer the app's views/errors directory, and fall back to the stock error pages.
revel.MainTemplateLoader = revel.NewTemplateLoader(
[]string{filepath.Join(revel.RevelPath, "templates")})
revel.MainTemplateLoader.Refresh()
if err := revel.MainTemplateLoader.Refresh(); err != nil {
revel.ERROR.Println(err)
}
addr := revel.HttpAddr
addr := revel.HTTPAddr
port := revel.Config.IntDefault("harness.port", 0)
scheme := "http"
if revel.HttpSsl {
if revel.HTTPSsl {
scheme = "https"
}
@@ -110,7 +115,7 @@ func NewHarness() *Harness {
proxy: httputil.NewSingleHostReverseProxy(serverURL),
}
if revel.HttpSsl {
if revel.HTTPSsl {
harness.proxy.Transport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
@@ -166,13 +171,16 @@ func (h *Harness) Run() {
watcher.Listen(h, paths...)
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)
var err error
if revel.HttpSsl {
err = http.ListenAndServeTLS(addr, revel.HttpSslCert,
revel.HttpSslKey, h)
if revel.HTTPSsl {
err = http.ListenAndServeTLS(
addr,
revel.HTTPSslCert,
revel.HTTPSslKey,
h)
} else {
err = http.ListenAndServe(addr, h)
}
@@ -213,7 +221,7 @@ func proxyWebsocket(w http.ResponseWriter, r *http.Request, host string) {
d net.Conn
err error
)
if revel.HttpSsl {
if revel.HTTPSsl {
// since this proxy isn't used in production,
// it's OK to set InsecureSkipVerify to true
// no need to add another configuration option.
@@ -236,8 +244,14 @@ func proxyWebsocket(w http.ResponseWriter, r *http.Request, host string) {
revel.ERROR.Printf("Hijack error: %v", err)
return
}
defer nc.Close()
defer d.Close()
defer func() {
if err = nc.Close(); err != nil {
revel.ERROR.Println(err)
}
if err = d.Close(); err != nil {
revel.ERROR.Println(err)
}
}()
err = r.Write(d)
if err != nil {

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package harness
// This file handles the app code introspection.
@@ -25,7 +29,7 @@ type SourceInfo struct {
StructSpecs []*TypeInfo
// ValidationKeys provides a two-level lookup. The keys are:
// 1. The fully-qualified function name,
// e.g. "github.com/revel/samples/chat/app/controllers.(*Application).Action"
// e.g. "github.com/revel/examples/chat/app/controllers.(*Application).Action"
// 2. Within that func's file, the line number of the (overall) expression statement.
// e.g. the line returned from runtime.Caller()
// The result of the lookup the name of variable being validated.
@@ -44,7 +48,7 @@ type SourceInfo struct {
// TypeInfo summarizes information about a struct type in the app source code.
type TypeInfo struct {
StructName string // e.g. "Application"
ImportPath string // e.g. "github.com/revel/samples/chat/app/controllers"
ImportPath string // e.g. "github.com/revel/examples/chat/app/controllers"
PackageName string // e.g. "controllers"
MethodSpecs []*MethodSpec
@@ -60,12 +64,14 @@ type methodCall struct {
Names []string
}
// MethodSpec holds the information of one Method
type MethodSpec struct {
Name string // Name of the method, e.g. "Index"
Args []*MethodArg // Argument descriptors
RenderCalls []*methodCall // Descriptions of Render() invocations from this Method.
}
// MethodArg holds the information of one argument
type MethodArg struct {
Name string // Name of the argument.
TypeExpr TypeExpr // The name of the type, e.g. "int", "*pkg.UserType"
@@ -80,8 +86,9 @@ type embeddedTypeName struct {
// receiver.
type methodMap map[string][]*MethodSpec
// Parse the app controllers directory and return a list of the controller types found.
// Returns a CompileError if the parsing fails.
// ProcessSource parses the app controllers directory and
// returns a list of the controller types found.
// Otherwise CompileError if the parsing fails.
func ProcessSource(roots []string) (*SourceInfo, *revel.Error) {
var (
srcInfo *SourceInfo
@@ -120,7 +127,7 @@ func ProcessSource(roots []string) (*SourceInfo, *revel.Error) {
}, 0)
if err != nil {
if errList, ok := err.(scanner.ErrorList); ok {
var pos token.Position = errList[0].Pos
var pos = errList[0].Pos
compileError = &revel.Error{
SourceType: ".go source",
Title: "Go Compilation Error",
@@ -139,6 +146,8 @@ func ProcessSource(roots []string) (*SourceInfo, *revel.Error) {
return compileError
}
// This is exception, err alredy checked above. Here just a print
ast.Print(nil, err)
log.Fatalf("Failed to parse dir: %s", err)
}
@@ -419,7 +428,7 @@ func appendAction(fset *token.FileSet, mm methodMap, decl ast.Decl, pkgImportPat
if selExpr.Sel.Name != "Result" {
return
}
if pkgIdent, ok := selExpr.X.(*ast.Ident); !ok || imports[pkgIdent.Name] != revel.REVEL_IMPORT_PATH {
if pkgIdent, ok := selExpr.X.(*ast.Ident); !ok || imports[pkgIdent.Name] != revel.RevelImportPath {
return
}
@@ -490,7 +499,7 @@ func appendAction(fset *token.FileSet, mm methodMap, decl ast.Decl, pkgImportPat
})
var recvTypeName string
var recvType ast.Expr = funcDecl.Recv.List[0].Type
var recvType = funcDecl.Recv.List[0].Type
if recvStarType, ok := recvType.(*ast.StarExpr); ok {
recvTypeName = recvStarType.X.(*ast.Ident).Name
} else {
@@ -597,7 +606,7 @@ func getValidationParameter(funcDecl *ast.FuncDecl, imports map[string]string) *
continue
}
if selExpr.Sel.Name == "Validation" && imports[xIdent.Name] == revel.REVEL_IMPORT_PATH {
if selExpr.Sel.Name == "Validation" && imports[xIdent.Name] == revel.RevelImportPath {
return field.Names[0].Obj
}
}
@@ -673,16 +682,20 @@ func (s *SourceInfo) TypesThatEmbed(targetType string) (filtered []*TypeInfo) {
return
}
// ControllerSpecs returns the all the contollers that embeds
// `revel.Controller`
func (s *SourceInfo) ControllerSpecs() []*TypeInfo {
if s.controllerSpecs == nil {
s.controllerSpecs = s.TypesThatEmbed(revel.REVEL_IMPORT_PATH + ".Controller")
s.controllerSpecs = s.TypesThatEmbed(revel.RevelImportPath + ".Controller")
}
return s.controllerSpecs
}
// TestSuites returns the all the Application tests that embeds
// `testing.TestSuite`
func (s *SourceInfo) TestSuites() []*TypeInfo {
if s.testSuites == nil {
s.testSuites = s.TypesThatEmbed(revel.REVEL_IMPORT_PATH + "/testing.TestSuite")
s.testSuites = s.TypesThatEmbed(revel.RevelImportPath + "/testing.TestSuite")
}
return s.testSuites
}
@@ -705,7 +718,7 @@ func (e TypeExpr) TypeName(pkgOverride string) string {
return e.Expr[:e.pkgIndex] + pkgName + "." + e.Expr[e.pkgIndex:]
}
// This returns the syntactic expression for referencing this type in Go.
// NewTypeExpr returns the syntactic expression for referencing this type in Go.
func NewTypeExpr(pkgName string, expr ast.Expr) TypeExpr {
switch t := expr.(type) {
case *ast.Ident:
@@ -731,35 +744,40 @@ func NewTypeExpr(pkgName string, expr ast.Expr) TypeExpr {
return TypeExpr{Valid: false}
}
var _BUILTIN_TYPES = map[string]struct{}{
"bool": struct{}{},
"byte": struct{}{},
"complex128": struct{}{},
"complex64": struct{}{},
"error": struct{}{},
"float32": struct{}{},
"float64": struct{}{},
"int": struct{}{},
"int16": struct{}{},
"int32": struct{}{},
"int64": struct{}{},
"int8": struct{}{},
"rune": struct{}{},
"string": struct{}{},
"uint": struct{}{},
"uint16": struct{}{},
"uint32": struct{}{},
"uint64": struct{}{},
"uint8": struct{}{},
"uintptr": struct{}{},
var builtInTypes = map[string]struct{}{
"bool": {},
"byte": {},
"complex128": {},
"complex64": {},
"error": {},
"float32": {},
"float64": {},
"int": {},
"int16": {},
"int32": {},
"int64": {},
"int8": {},
"rune": {},
"string": {},
"uint": {},
"uint16": {},
"uint32": {},
"uint64": {},
"uint8": {},
"uintptr": {},
}
// IsBuiltinType checks the given type is built-in types of Go
func IsBuiltinType(name string) bool {
_, ok := _BUILTIN_TYPES[name]
_, ok := builtInTypes[name]
return ok
}
func importPathFromPath(root string) string {
vendoringPath := revel.BasePath + "/vendor/"
if strings.HasPrefix(root, vendoringPath) {
return filepath.ToSlash(root[len(vendoringPath):])
}
for _, gopath := range filepath.SplitList(build.Default.GOPATH) {
srcPath := filepath.Join(gopath, "src")
if strings.HasPrefix(root, srcPath) {

View File

@@ -1,7 +1,10 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package harness
import (
"github.com/revel/revel"
"go/ast"
"go/parser"
"go/token"
@@ -10,6 +13,8 @@ import (
"reflect"
"strings"
"testing"
"github.com/revel/revel"
)
const validationKeysSource = `
@@ -77,7 +82,7 @@ func TestGetValidationKeys(t *testing.T) {
}
for i, decl := range file.Decls {
lineKeys := getValidationKeys(fset, decl.(*ast.FuncDecl), map[string]string{"revel": revel.REVEL_IMPORT_PATH})
lineKeys := getValidationKeys(fset, decl.(*ast.FuncDecl), map[string]string{"revel": revel.RevelImportPath})
for k, v := range expectedValidationKeys[i] {
if lineKeys[k] != v {
t.Errorf("Not found - %d: %v - Actual Map: %v", k, v, lineKeys)
@@ -91,18 +96,18 @@ func TestGetValidationKeys(t *testing.T) {
}
var TypeExprs = map[string]TypeExpr{
"int": TypeExpr{"int", "", 0, true},
"*int": TypeExpr{"*int", "", 1, true},
"[]int": TypeExpr{"[]int", "", 2, true},
"...int": TypeExpr{"[]int", "", 2, true},
"[]*int": TypeExpr{"[]*int", "", 3, true},
"...*int": TypeExpr{"[]*int", "", 3, true},
"MyType": TypeExpr{"MyType", "pkg", 0, true},
"*MyType": TypeExpr{"*MyType", "pkg", 1, true},
"[]MyType": TypeExpr{"[]MyType", "pkg", 2, true},
"...MyType": TypeExpr{"[]MyType", "pkg", 2, true},
"[]*MyType": TypeExpr{"[]*MyType", "pkg", 3, true},
"...*MyType": TypeExpr{"[]*MyType", "pkg", 3, true},
"int": {"int", "", 0, true},
"*int": {"*int", "", 1, true},
"[]int": {"[]int", "", 2, true},
"...int": {"[]int", "", 2, true},
"[]*int": {"[]*int", "", 3, true},
"...*int": {"[]*int", "", 3, true},
"MyType": {"MyType", "pkg", 0, true},
"*MyType": {"*MyType", "pkg", 1, true},
"[]MyType": {"[]MyType", "pkg", 2, true},
"...MyType": {"[]MyType", "pkg", 2, true},
"[]*MyType": {"[]*MyType", "pkg", 3, true},
"...*MyType": {"[]*MyType", "pkg", 3, true},
}
func TestTypeExpr(t *testing.T) {
@@ -125,10 +130,10 @@ func TestTypeExpr(t *testing.T) {
}
if array {
expr = &ast.ArrayType{expr.Pos(), nil, expr}
expr = &ast.ArrayType{Lbrack: expr.Pos(), Len: nil, Elt: expr}
}
if ellipsis {
expr = &ast.Ellipsis{expr.Pos(), expr}
expr = &ast.Ellipsis{Ellipsis: expr.Pos(), Elt: expr}
}
actual := NewTypeExpr("pkg", expr)
@@ -139,17 +144,17 @@ func TestTypeExpr(t *testing.T) {
}
func TestProcessBookingSource(t *testing.T) {
revel.Init("prod", "github.com/revel/samples/booking", "")
revel.Init("prod", "github.com/revel/examples/booking", "")
sourceInfo, err := ProcessSource([]string{revel.AppPath})
if err != nil {
t.Fatal("Failed to process booking source with error:", err)
}
CONTROLLER_PKG := "github.com/revel/samples/booking/app/controllers"
controllerPackage := "github.com/revel/examples/booking/app/controllers"
expectedControllerSpecs := []*TypeInfo{
{"GorpController", CONTROLLER_PKG, "controllers", nil, nil},
{"Application", CONTROLLER_PKG, "controllers", nil, nil},
{"Hotels", CONTROLLER_PKG, "controllers", nil, nil},
{"GorpController", controllerPackage, "controllers", nil, nil},
{"Application", controllerPackage, "controllers", nil, nil},
{"Hotels", controllerPackage, "controllers", nil, nil},
}
if len(sourceInfo.ControllerSpecs()) != len(expectedControllerSpecs) {
t.Errorf("Unexpected number of controllers found. Expected %d, Found %d",
@@ -177,7 +182,7 @@ NEXT_TEST:
}
func BenchmarkProcessBookingSource(b *testing.B) {
revel.Init("", "github.com/revel/samples/booking", "")
revel.Init("", "github.com/revel/examples/booking", "")
revel.TRACE = log.New(ioutil.Discard, "", 0)
b.ResetTimer()

View File

@@ -1,9 +1,12 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"os"
"path"
"path/filepath"
"strings"
@@ -27,7 +30,7 @@ WARNING: The target path will be completely deleted, if it already exists!
For example:
revel build github.com/revel/samples/chat /tmp/chat
revel build github.com/revel/examples/chat /tmp/chat
`,
}
@@ -41,7 +44,7 @@ func buildApp(args []string) {
return
}
appImportPath, destPath, mode := args[0], args[1], "dev"
appImportPath, destPath, mode := args[0], args[1], DefaultRunMode
if len(args) >= 3 {
mode = args[2]
}
@@ -52,12 +55,17 @@ func buildApp(args []string) {
// First, verify that it is either already empty or looks like a previous
// build (to avoid clobbering anything)
if exists(destPath) && !empty(destPath) && !exists(path.Join(destPath, "run.sh")) {
if exists(destPath) && !empty(destPath) && !exists(filepath.Join(destPath, "run.sh")) {
errorf("Abort: %s exists and does not look like a build directory.", destPath)
}
os.RemoveAll(destPath)
os.MkdirAll(destPath, 0777)
if err := os.RemoveAll(destPath); err != nil && !os.IsNotExist(err) {
revel.ERROR.Fatalln(err)
}
if err := os.MkdirAll(destPath, 0777); err != nil {
revel.ERROR.Fatalln(err)
}
app, reverr := harness.Build()
panicOnError(reverr, "Failed to build")
@@ -69,14 +77,14 @@ func buildApp(args []string) {
// - app
// Revel and the app are in a directory structure mirroring import path
srcPath := path.Join(destPath, "src")
destBinaryPath := path.Join(destPath, filepath.Base(app.BinaryPath))
tmpRevelPath := path.Join(srcPath, filepath.FromSlash(revel.REVEL_IMPORT_PATH))
srcPath := filepath.Join(destPath, "src")
destBinaryPath := filepath.Join(destPath, filepath.Base(app.BinaryPath))
tmpRevelPath := filepath.Join(srcPath, filepath.FromSlash(revel.RevelImportPath))
mustCopyFile(destBinaryPath, app.BinaryPath)
mustChmod(destBinaryPath, 0755)
mustCopyDir(path.Join(tmpRevelPath, "conf"), path.Join(revel.RevelPath, "conf"), nil)
mustCopyDir(path.Join(tmpRevelPath, "templates"), path.Join(revel.RevelPath, "templates"), nil)
mustCopyDir(path.Join(srcPath, filepath.FromSlash(appImportPath)), revel.BasePath, nil)
_ = mustCopyDir(filepath.Join(tmpRevelPath, "conf"), filepath.Join(revel.RevelPath, "conf"), nil)
_ = mustCopyDir(filepath.Join(tmpRevelPath, "templates"), filepath.Join(revel.RevelPath, "templates"), nil)
_ = mustCopyDir(filepath.Join(srcPath, filepath.FromSlash(appImportPath)), revel.BasePath, nil)
// Find all the modules used and copy them over.
config := revel.Config.Raw()
@@ -99,14 +107,14 @@ func buildApp(args []string) {
}
}
for importPath, fsPath := range modulePaths {
mustCopyDir(path.Join(srcPath, importPath), fsPath, nil)
_ = mustCopyDir(filepath.Join(srcPath, importPath), fsPath, nil)
}
tmplData, runShPath := map[string]interface{}{
"BinName": filepath.Base(app.BinaryPath),
"ImportPath": appImportPath,
"Mode": mode,
}, path.Join(destPath, "run.sh")
}, filepath.Join(destPath, "run.sh")
mustRenderTemplate(
runShPath,

View File

@@ -1,10 +1,14 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"go/build"
"os"
"path"
"path/filepath"
)
var cmdClean = &Command{
@@ -15,7 +19,7 @@ Clean the Revel web application named by the given import path.
For example:
revel clean github.com/revel/samples/chat
revel clean github.com/revel/examples/chat
It removes the app/tmp and app/routes directory.
`,
@@ -38,8 +42,8 @@ func cleanApp(args []string) {
}
purgeDirs := []string{
path.Join(appPkg.Dir, "app", "tmp"),
path.Join(appPkg.Dir, "app", "routes"),
filepath.Join(appPkg.Dir, "app", "tmp"),
filepath.Join(appPkg.Dir, "app", "routes"),
}
for _, dir := range purgeDirs {

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package main
import (
@@ -46,6 +50,7 @@ var (
// revel related paths
revelPkg *build.Package
revelCmdPkg *build.Package
appPath string
appName string
basePath string
@@ -148,7 +153,7 @@ func setApplicationPath(args []string) {
errorf("Abort: Import path %s already exists.\n", importPath)
}
revelPkg, err = build.Import(revel.REVEL_IMPORT_PATH, "", build.FindOnly)
revelPkg, err = build.Import(revel.RevelImportPath, "", build.FindOnly)
if err != nil {
errorf("Abort: Could not find Revel source code: %s\n", err)
}
@@ -190,7 +195,12 @@ func setSkeletonPath(args []string) {
} else {
// use the revel default
skeletonPath = filepath.Join(revelPkg.Dir, "skeleton")
revelCmdPkg, err = build.Import(RevelCmdImportPath, "", build.FindOnly)
if err != nil {
errorf("Abort: Could not find Revel Cmd source code: %s\n", err)
}
skeletonPath = filepath.Join(revelCmdPkg.Dir, "revel", "skeleton")
}
}
@@ -199,7 +209,7 @@ func copyNewAppFiles() {
err = os.MkdirAll(appPath, 0777)
panicOnError(err, "Failed to create directory "+appPath)
mustCopyDir(appPath, skeletonPath, map[string]interface{}{
_ = mustCopyDir(appPath, skeletonPath, map[string]interface{}{
// app.conf
"AppName": appName,
"BasePath": basePath,

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package main
import (
@@ -23,7 +27,7 @@ Run mode defaults to "dev".
For example:
revel package github.com/revel/samples/chat
revel package github.com/revel/examples/chat
`,
}
@@ -38,7 +42,7 @@ func packageApp(args []string) {
}
// Determine the run mode.
mode := "dev"
mode := DefaultRunMode
if len(args) >= 2 {
mode = args[1]
}
@@ -48,7 +52,9 @@ func packageApp(args []string) {
// Remove the archive if it already exists.
destFile := filepath.Base(revel.BasePath) + ".tar.gz"
os.Remove(destFile)
if err := os.Remove(destFile); err != nil && !os.IsNotExist(err) {
revel.ERROR.Fatal(err)
}
// Collect stuff in a temp directory.
tmpDir, err := ioutil.TempDir("", filepath.Base(revel.BasePath))

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
// The command line tool for running Revel apps.
package main
@@ -15,12 +19,21 @@ import (
"github.com/agtorre/gocolorize"
)
const (
// RevelCmdImportPath Revel framework cmd tool import path
RevelCmdImportPath = "github.com/revel/cmd"
// DefaultRunMode for revel's application
DefaultRunMode = "dev"
)
// Command structure cribbed from the genius organization of the "go" command.
type Command struct {
Run func(args []string)
UsageLine, Short, Long string
}
// Name returns command name from usage line
func (cmd *Command) Name() string {
name := cmd.UsageLine
i := strings.Index(name, " ")

View File

@@ -1,9 +1,15 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package main
import (
"go/build"
"strconv"
"github.com/revel/cmd/harness"
"github.com/revel/revel"
"strconv"
)
var cmdRun = &Command{
@@ -14,7 +20,7 @@ Run the Revel web application named by the given import path.
For example, to run the chat room sample application:
revel run github.com/revel/samples/chat dev
revel run github.com/revel/examples/chat dev
The run mode is used to select which set of app.conf configuration should
apply and may be used to determine logic in the application itself.
@@ -23,44 +29,100 @@ Run mode defaults to "dev".
You can set a port as an optional third parameter. For example:
revel run github.com/revel/samples/chat prod 8080`,
revel run github.com/revel/examples/chat prod 8080`,
}
// RunArgs holds revel run parameters
type RunArgs struct {
ImportPath string
Mode string
Port int
}
func init() {
cmdRun.Run = runApp
}
func runApp(args []string) {
if len(args) == 0 {
errorf("No import path given.\nRun 'revel help run' for usage.\n")
func parseRunArgs(args []string) *RunArgs {
inputArgs := RunArgs{
ImportPath: importPathFromCurrentDir(),
Mode: DefaultRunMode,
Port: revel.HTTPPort,
}
// Determine the run mode.
mode := "dev"
if len(args) >= 2 {
mode = args[1]
}
// Find and parse app.conf
revel.Init(mode, args[0], "")
revel.LoadMimeConfig()
// Determine the override port, if any.
port := revel.HttpPort
if len(args) == 3 {
var err error
if port, err = strconv.Atoi(args[2]); err != nil {
switch len(args) {
case 3:
// Possibile combinations
// revel run [import-path] [run-mode] [port]
port, err := strconv.Atoi(args[2])
if err != nil {
errorf("Failed to parse port as integer: %s", args[2])
}
inputArgs.ImportPath = args[0]
inputArgs.Mode = args[1]
inputArgs.Port = port
case 2:
// Possibile combinations
// 1. revel run [import-path] [run-mode]
// 2. revel run [import-path] [port]
// 3. revel run [run-mode] [port]
if _, err := build.Import(args[0], "", build.FindOnly); err == nil {
// 1st arg is the import path
inputArgs.ImportPath = args[0]
if port, err := strconv.Atoi(args[1]); err == nil {
// 2nd arg is the port number
inputArgs.Port = port
} else {
// 2nd arg is the run mode
inputArgs.Mode = args[1]
}
} else {
// 1st arg is the run mode
port, err := strconv.Atoi(args[1])
if err != nil {
errorf("Failed to parse port as integer: %s", args[1])
}
inputArgs.Mode = args[0]
inputArgs.Port = port
}
case 1:
// Possibile combinations
// 1. revel run [import-path]
// 2. revel run [port]
// 3. revel run [run-mode]
if _, err := build.Import(args[0], "", build.FindOnly); err == nil {
// 1st arg is the import path
inputArgs.ImportPath = args[0]
} else if port, err := strconv.Atoi(args[0]); err == nil {
// 1st arg is the port number
inputArgs.Port = port
} else {
// 1st arg is the run mode
inputArgs.Mode = args[0]
}
}
revel.INFO.Printf("Running %s (%s) in %s mode\n", revel.AppName, revel.ImportPath, mode)
return &inputArgs
}
func runApp(args []string) {
runArgs := parseRunArgs(args)
// Find and parse app.conf
revel.Init(runArgs.Mode, runArgs.ImportPath, "")
revel.LoadMimeConfig()
// fallback to default port
if runArgs.Port == 0 {
runArgs.Port = revel.HTTPPort
}
revel.INFO.Printf("Running %s (%s) in %s mode\n", revel.AppName, revel.ImportPath, runArgs.Mode)
revel.TRACE.Println("Base path:", revel.BasePath)
// 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) {
revel.TRACE.Println("Running in watched mode.")
revel.HttpPort = port
revel.HTTPPort = runArgs.Port
harness.NewHarness().Run() // Never returns.
}
@@ -70,6 +132,6 @@ func runApp(args []string) {
if err != nil {
errorf("Failed to build app: %s", err)
}
app.Port = port
app.Port = runArgs.Port
app.Cmd().Run()
}

3
revel/skeleton/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
test-results/
tmp/
routes/

43
revel/skeleton/README.md Normal file
View File

@@ -0,0 +1,43 @@
# Welcome to Revel
A high-productivity web framework for the [Go language](http://www.golang.org/).
### Start the web server:
revel run myapp
### Go to http://localhost:9000/ and you'll see:
"It works"
## Code Layout
The directory structure of a generated Revel application:
conf/ Configuration directory
app.conf Main app configuration file
routes Routes definition file
app/ App sources
init.go Interceptor registration
controllers/ App controllers go here
views/ Templates directory
messages/ Message files
public/ Public static assets
css/ CSS files
js/ Javascript files
images/ Image files
tests/ Test suites
## Help
* The [Getting Started with Revel](http://revel.github.io/tutorial/gettingstarted.html).
* The [Revel guides](http://revel.github.io/manual/index.html).
* The [Revel sample apps](http://revel.github.io/examples/index.html).
* The [API documentation](https://godoc.org/github.com/revel/revel).

View File

@@ -0,0 +1,13 @@
package controllers
import (
"github.com/revel/revel"
)
type App struct {
*revel.Controller
}
func (c App) Index() revel.Result {
return c.Render()
}

View File

@@ -0,0 +1,59 @@
package app
import (
"github.com/revel/revel"
)
var (
// AppVersion revel app version (ldflags)
AppVersion string
// BuildTime revel app build-time (ldflags)
BuildTime string
)
func init() {
// Filters is the default set of global filters.
revel.Filters = []revel.Filter{
revel.PanicFilter, // Recover from panics and display an error page instead.
revel.RouterFilter, // Use the routing table to select the right Action
revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
revel.ParamsFilter, // Parse parameters into Controller.Params.
revel.SessionFilter, // Restore and write the session cookie.
revel.FlashFilter, // Restore and write the flash cookie.
revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie.
revel.I18nFilter, // Resolve the requested language
HeaderFilter, // Add some security based headers
revel.InterceptorFilter, // Run interceptors around the action.
revel.CompressFilter, // Compress the result.
revel.ActionInvoker, // Invoke the action.
}
// register startup functions with OnAppStart
// revel.DevMode and revel.RunMode only work inside of OnAppStart. See Example Startup Script
// ( order dependent )
// revel.OnAppStart(ExampleStartupScript)
// revel.OnAppStart(InitDB)
// revel.OnAppStart(FillCache)
}
// HeaderFilter adds common security headers
// TODO turn this into revel.HeaderFilter
// should probably also have a filter for CSRF
// not sure if it can go in the same filter or not
var HeaderFilter = func(c *revel.Controller, fc []revel.Filter) {
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-Content-Type-Options", "nosniff")
fc[0](c, fc[1:]) // Execute the next filter stage.
}
//func ExampleStartupScript() {
// // revel.DevMod and revel.RunMode work here
// // Use this script to check for dev mode and set dev/prod startup scripts here!
// if revel.DevMode == true {
// // Dev mode
// }
//}

View File

@@ -0,0 +1,21 @@
{{set . "title" "Home"}}
{{template "header.html" .}}
<header class="jumbotron" style="background-color:#A9F16C">
<div class="container">
<div class="row">
<h1>It works!</h1>
<p></p>
</div>
</div>
</header>
<div class="container">
<div class="row">
<div class="span6">
{{template "flash.html" .}}
</div>
</div>
</div>
{{template "footer.html" .}}

View File

@@ -0,0 +1,64 @@
<style type="text/css">
#sidebar {
position: absolute;
right: 0px;
top:69px;
max-width: 75%;
z-index: 1000;
background-color: #fee;
border: thin solid grey;
padding: 10px;
}
#toggleSidebar {
position: absolute;
right: 0px;
top: 50px;
background-color: #fee;
}
</style>
<div id="sidebar" style="display:none;">
<h4>Available pipelines</h4>
<dl>
{{ range $index, $value := .}}
<dt>{{$index}}</dt>
<dd>{{$value}}</dd>
{{end}}
</dl>
<h4>Flash</h4>
<dl>
{{ range $index, $value := .flash}}
<dt>{{$index}}</dt>
<dd>{{$value}}</dd>
{{end}}
</dl>
<h4>Errors</h4>
<dl>
{{ range $index, $value := .errors}}
<dt>{{$index}}</dt>
<dd>{{$value}}</dd>
{{end}}
</dl>
</div>
<a id="toggleSidebar" href="#" class="toggles"><i class="glyphicon glyphicon-chevron-left"></i></a>
<script>
$sidebar = 0;
$('#toggleSidebar').click(function() {
if ($sidebar === 1) {
$('#sidebar').hide();
$('#toggleSidebar i').addClass('glyphicon-chevron-left');
$('#toggleSidebar i').removeClass('glyphicon-chevron-right');
$sidebar = 0;
}
else {
$('#sidebar').show();
$('#toggleSidebar i').addClass('glyphicon-chevron-right');
$('#toggleSidebar i').removeClass('glyphicon-chevron-left');
$sidebar = 1;
}
return false;
});
</script>

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Not found</title>
</head>
<body>
{{if eq .RunMode "dev"}}
{{template "errors/404-dev.html" .}}
{{else}}
{{with .Error}}
<h1>
{{.Title}}
</h1>
<p>
{{.Description}}
</p>
{{end}}
{{end}}
</body>
</html>

View File

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>Application error</title>
</head>
<body>
{{if eq .RunMode "dev"}}
{{template "errors/500-dev.html" .}}
{{else}}
<h1>Oops, an error occured</h1>
<p>
This exception has been logged.
</p>
{{end}}
</body>
</html>

View File

@@ -0,0 +1,18 @@
{{if .flash.success}}
<div class="alert alert-success">
{{.flash.success}}
</div>
{{end}}
{{if or .errors .flash.error}}
<div class="alert alert-danger">
{{if .flash.error}}
{{.flash.error}}
{{end}}
<ul style="margin-top:10px;">
{{range .errors}}
<li>{{.}}</li>
{{end}}
</ul>
</div>
{{end}}

View File

@@ -0,0 +1,5 @@
{{if eq .RunMode "dev"}}
{{template "debug.html" .}}
{{end}}
</body>
</html>

View File

@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<title>{{.title}}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="/public/css/bootstrap-3.3.6.min.css">
<link rel="shortcut icon" type="image/png" href="/public/img/favicon.png">
<script src="/public/js/jquery-2.2.4.min.js"></script>
<script src="/public/js/bootstrap-3.3.6.min.js"></script>
{{range .moreStyles}}
<link rel="stylesheet" type="text/css" href="/public/{{.}}">
{{end}}
{{range .moreScripts}}
<script src="/public/{{.}}" type="text/javascript" charset="utf-8"></script>
{{end}}
</head>
<body>

View File

@@ -0,0 +1,258 @@
################################################################################
# Revel configuration file
# More info at http://revel.github.io/manual/appconf.html
################################################################################
# Sets `revel.AppName` for use in-app.
# Example:
# `if revel.AppName {...}`
app.name = {{ .AppName }}
# A secret string which is passed to cryptographically sign the cookie to prevent
# (and detect) user modification.
# Keep this string secret or users will be able to inject arbitrary cookie values
# into your application
app.secret = {{ .Secret }}
# Revel running behind proxy like nginx, haproxy, etc.
app.behind.proxy = false
# The IP address on which to listen.
http.addr =
# The port on which to listen.
http.port = 9000
# Whether to use SSL or not.
http.ssl = false
# Path to an X509 certificate file, if using SSL.
#http.sslcert =
# Path to an X509 certificate key, if using SSL.
#http.sslkey =
# Timeout specifies a time limit for request (in seconds) made by a single client.
# A Timeout of zero means no timeout.
http.timeout.read = 90
http.timeout.write = 60
# For any cookies set by Revel (Session,Flash,Error) these properties will set
# the fields of:
# http://golang.org/pkg/net/http/#Cookie
#
# Each cookie set by Revel is prefixed with this string.
cookie.prefix = REVEL
# A secure cookie has the secure attribute enabled and is only used via HTTPS,
# ensuring that the cookie is always encrypted when transmitting from client to
# server. This makes the cookie less likely to be exposed to cookie theft via
# eavesdropping.
#
# Defaults to false. If 'http.ssl' is enabled, this will be defaulted to true.
# This should only be true when Revel is handling SSL connections. If you are
# using a proxy in front of revel (Nginx, Apache, etc), then this should be left
# as false.
# cookie.secure = false
# Limit cookie access to a given domain.
#cookie.domain =
# Define when your session cookie expires.
# Values:
# "720h"
# A time duration (http://golang.org/pkg/time/#ParseDuration) after which
# the cookie expires and the session is invalid.
# "session"
# Sets a session cookie which invalidates the session when the user close
# the browser.
session.expires = 720h
# The date format used by Revel. Possible formats defined by the Go `time`
# package (http://golang.org/pkg/time/#Parse)
format.date = 2006-01-02
format.datetime = 2006-01-02 15:04
# Determines whether the template rendering should use chunked encoding.
# Chunked encoding can decrease the time to first byte on the client side by
# sending data before the entire template has been fully rendered.
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.
i18n.default_language = en
# The default format when message is missing.
# The original message shows in %s
#i18n.unknown_format = "??? %s ???"
# Module to serve static content such as CSS, JavaScript and Media files
# Allows Routes like this:
# `Static.ServeModule("modulename","public")`
module.static=github.com/revel/modules/static
################################################################################
# Section: dev
# This section is evaluated when running Revel in dev mode. Like so:
# `revel run path/to/myapp`
[dev]
# This sets `revel.DevMode` for use in-app.
# Example:
# `if revel.DevMode {...}`
# or in your templates with
# `{{.DevMode}}`
# Values:
# "true"
# Sets `DevMode` to `true`.
# "false"
# Sets `DevMode` to `false`.
mode.dev = true
# Pretty print JSON/XML when calling RenderJSON/RenderXML
# Values:
# "true"
# Enables pretty printing.
# "false"
# Disables pretty printing.
results.pretty = true
# Watch your applicaton files for changes and automatically rebuild
# Values:
# "true"
# Enables auto rebuilding.
# "false"
# Disables auto rebuilding.
watch = true
# Define when to rebuild new changes.
# Values:
# "normal"
# Rebuild when a new request is received and changes have been detected.
# "eager"
# Rebuild as soon as changes are detected.
watch.mode = normal
# Watch the entire `$GOPATH` for changes.
# Values:
# "true"
# Includes `$GOPATH` in watch path.
# "false"
# Excludes `$GOPATH` from watch path. Default value.
#watch.gopath = true
# Module to run code tests in the browser
# See:
# http://revel.github.io/manual/testing.html
module.testrunner = github.com/revel/modules/testrunner
# Where to log the various Revel logs
# Values:
# "off"
# Disable log output.
# "stdout"
# Log to OS's standard output.
# "stderr"
# Log to Os's standard error output. Default value.
# "relative/path/to/log"
# Log to file.
log.trace.output = off
log.info.output = stderr
log.warn.output = stderr
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
# 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 /
log.request.output = stderr
################################################################################
# Section: prod
# This section is evaluated when running Revel in production mode. Like so:
# `revel run path/to/myapp prod`
# See:
# [dev] section for documentation of the various settings
[prod]
mode.dev = false
results.pretty = false
watch = false
module.testrunner =
log.trace.output = off
log.info.output = off
log.warn.output = log/%(app.name)s.log
log.error.output = log/%(app.name)s.log
# Revel log flags. Possible flags defined by the Go `log` package,
# 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:
# log.request.output = %(app.name)s-request.log
log.request.output = off

View File

@@ -0,0 +1,19 @@
# Routes Config
#
# This file defines all application routes (Higher priority routes first)
#
module:testrunner
# module:jobs
GET / App.Index
# Ignore favicon requests
GET /favicon.ico 404
# Map static resources from the /app/public folder to the /public path
GET /public/*filepath Static.Serve("public")
# Catch all
* /:controller/:action :controller.:action

View File

@@ -0,0 +1,7 @@
# Sample messages file for the English language (en)
# Message file extensions should be ISO 639-1 codes (http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)
# Sections within each message file can optionally override the defaults using ISO 3166-1 alpha-2 codes (http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)
# See also:
# - http://www.rfc-editor.org/rfc/bcp/bcp47.txt
# - http://www.w3.org/International/questions/qa-accept-lang-locales

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,23 @@
package tests
import (
"github.com/revel/revel/testing"
)
type AppTest struct {
testing.TestSuite
}
func (t *AppTest) Before() {
println("Set up")
}
func (t *AppTest) TestThatIndexPageWorks() {
t.Get("/")
t.AssertOk()
t.AssertContentType("text/html; charset=utf-8")
}
func (t *AppTest) After() {
println("Tear down")
}

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package main
import (
@@ -7,7 +11,7 @@ import (
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"time"
@@ -24,7 +28,7 @@ Run all tests for the Revel app named by the given import path.
For example, to run the booking sample application's tests:
revel test github.com/revel/samples/booking dev
revel test github.com/revel/examples/booking dev
The run mode is used to select which set of app.conf configuration should
apply and may be used to determine logic in the application itself.
@@ -52,7 +56,7 @@ func testApp(args []string) {
errorf("No import path given.\nRun 'revel help test' for usage.\n")
}
mode := "dev"
mode := DefaultRunMode
if len(args) >= 2 {
mode = args[1]
}
@@ -61,25 +65,10 @@ func testApp(args []string) {
revel.Init(mode, args[0], "")
// Ensure that the testrunner is loaded in this mode.
testRunnerFound := false
for _, module := range revel.Modules {
if module.ImportPath == revel.Config.StringDefault("module.testrunner", "github.com/revel/modules/testrunner") {
testRunnerFound = true
break
}
}
if !testRunnerFound {
errorf(`Error: The testrunner module is not running.
You can add it to a run mode configuration with the following line:
module.testrunner = github.com/revel/modules/testrunner
`)
}
checkTestRunner()
// Create a directory to hold the test result files.
resultPath := path.Join(revel.BasePath, "test-results")
resultPath := filepath.Join(revel.BasePath, "test-results")
if err = os.RemoveAll(resultPath); err != nil {
errorf("Failed to remove test result directory %s: %s", resultPath, err)
}
@@ -88,9 +77,9 @@ You can add it to a run mode configuration with the following line:
}
// Direct all the output into a file in the test-results directory.
file, err := os.OpenFile(path.Join(resultPath, "app.log"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
file, err := os.OpenFile(filepath.Join(resultPath, "app.log"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
errorf("Failed to create log file: %s", err)
errorf("Failed to create test result log file: %s", err)
}
app, reverr := harness.Build()
@@ -108,109 +97,27 @@ You can add it to a run mode configuration with the following line:
defer cmd.Kill()
revel.INFO.Printf("Testing %s (%s) in %s mode\n", revel.AppName, revel.ImportPath, mode)
// Get a list of tests.
// Since this is the first request to the server, retry/sleep a couple times
// in case it hasn't finished starting up yet.
var (
testSuites []controllers.TestSuiteDesc
resp *http.Response
baseUrl = fmt.Sprintf("http://127.0.0.1:%d", revel.HttpPort)
)
for i := 0; ; i++ {
if resp, err = http.Get(baseUrl + "/@tests.list"); err == nil {
if resp.StatusCode == http.StatusOK {
break
}
}
if i < 3 {
time.Sleep(3 * time.Second)
continue
}
if err != nil {
errorf("Failed to request test list: %s", err)
} else {
errorf("Failed to request test list: non-200 response")
}
}
defer resp.Body.Close()
json.NewDecoder(resp.Body).Decode(&testSuites)
// Get a list of tests
var baseURL = fmt.Sprintf("http://127.0.0.1:%d", revel.HTTPPort)
testSuites, _ := getTestsList(baseURL)
// If a specific TestSuite[.Method] is specified, only run that suite/test
if len(args) == 3 {
testSuites = filterTestSuites(testSuites, args[2])
}
fmt.Printf("\n%d test suite%s to run.\n", len(testSuites), pluralize(len(testSuites), "", "s"))
testSuiteCount := len(*testSuites)
fmt.Printf("\n%d test suite%s to run.\n", testSuiteCount, pluralize(testSuiteCount, "", "s"))
fmt.Println()
// Load the result template, which we execute for each suite.
module, _ := revel.ModuleByName("testrunner")
TemplateLoader := revel.NewTemplateLoader([]string{path.Join(module.Path, "app", "views")})
if err := TemplateLoader.Refresh(); err != nil {
errorf("Failed to compile templates: %s", err)
}
resultTemplate, err := TemplateLoader.Template("TestRunner/SuiteResult.html")
if err != nil {
errorf("Failed to load suite result template: %s", err)
}
// Run each suite.
var (
overallSuccess = true
failedResults []controllers.TestSuiteResult
)
for _, suite := range testSuites {
// Print the name of the suite we're running.
name := suite.Name
if len(name) > 22 {
name = name[:19] + "..."
}
fmt.Printf("%-22s", name)
// Run every test.
startTime := time.Now()
suiteResult := controllers.TestSuiteResult{Name: suite.Name, Passed: true}
for _, test := range suite.Tests {
testUrl := baseUrl + "/@tests/" + suite.Name + "/" + test.Name
resp, err := http.Get(testUrl)
if err != nil {
errorf("Failed to fetch test result at url %s: %s", testUrl, err)
}
defer resp.Body.Close()
var testResult controllers.TestResult
json.NewDecoder(resp.Body).Decode(&testResult)
if !testResult.Passed {
suiteResult.Passed = false
}
suiteResult.Results = append(suiteResult.Results, testResult)
}
overallSuccess = overallSuccess && suiteResult.Passed
// Print result. (Just PASSED or FAILED, and the time taken)
suiteResultStr, suiteAlert := "PASSED", ""
if !suiteResult.Passed {
suiteResultStr, suiteAlert = "FAILED", "!"
failedResults = append(failedResults, suiteResult)
}
fmt.Printf("%8s%3s%6ds\n", suiteResultStr, suiteAlert, int(time.Since(startTime).Seconds()))
// Create the result HTML file.
suiteResultFilename := path.Join(resultPath,
fmt.Sprintf("%s.%s.html", suite.Name, strings.ToLower(suiteResultStr)))
suiteResultFile, err := os.Create(suiteResultFilename)
if err != nil {
errorf("Failed to create result file %s: %s", suiteResultFilename, err)
}
if err = resultTemplate.Render(suiteResultFile, suiteResult); err != nil {
errorf("Failed to render result template: %s", err)
}
}
failedResults, overallSuccess := runTestSuites(baseURL, resultPath, testSuites)
fmt.Println()
if overallSuccess {
writeResultFile(resultPath, "result.passed", "passed")
fmt.Println("All Tests Passed.")
} else {
for _, failedResult := range failedResults {
for _, failedResult := range *failedResults {
fmt.Printf("Failures:\n")
for _, result := range failedResult.Results {
if !result.Passed {
@@ -225,8 +132,8 @@ You can add it to a run mode configuration with the following line:
}
func writeResultFile(resultPath, name, content string) {
if err := ioutil.WriteFile(path.Join(resultPath, name), []byte(content), 0666); err != nil {
errorf("Failed to write result file %s: %s", path.Join(resultPath, name), err)
if err := ioutil.WriteFile(filepath.Join(resultPath, name), []byte(content), 0666); err != nil {
errorf("Failed to write result file %s: %s", filepath.Join(resultPath, name), err)
}
}
@@ -239,7 +146,7 @@ func pluralize(num int, singular, plural string) string {
// Filters test suites and individual tests to match
// the parsed command line parameter
func filterTestSuites(suites []controllers.TestSuiteDesc, suiteArgument string) []controllers.TestSuiteDesc {
func filterTestSuites(suites *[]controllers.TestSuiteDesc, suiteArgument string) *[]controllers.TestSuiteDesc {
var suiteName, testName string
argArray := strings.Split(suiteArgument, ".")
suiteName = argArray[0]
@@ -249,20 +156,20 @@ func filterTestSuites(suites []controllers.TestSuiteDesc, suiteArgument string)
if len(argArray) == 2 {
testName = argArray[1]
}
for _, suite := range suites {
for _, suite := range *suites {
if suite.Name != suiteName {
continue
}
if testName == "" {
return []controllers.TestSuiteDesc{suite}
return &[]controllers.TestSuiteDesc{suite}
}
// Only run a particular test in a suite
for _, test := range suite.Tests {
if test.Name != testName {
continue
}
return []controllers.TestSuiteDesc{
controllers.TestSuiteDesc{
return &[]controllers.TestSuiteDesc{
{
Name: suite.Name,
Tests: []controllers.TestDesc{test},
},
@@ -273,3 +180,125 @@ func filterTestSuites(suites []controllers.TestSuiteDesc, suiteArgument string)
errorf("Couldn't find test suite %s", suiteName)
return nil
}
func checkTestRunner() {
testRunnerFound := false
for _, module := range revel.Modules {
if module.ImportPath == revel.Config.StringDefault("module.testrunner", "github.com/revel/modules/testrunner") {
testRunnerFound = true
break
}
}
if !testRunnerFound {
errorf(`Error: The testrunner module is not running.
You can add it to a run mode configuration with the following line:
module.testrunner = github.com/revel/modules/testrunner
`)
}
}
// Get a list of tests from server.
// Since this is the first request to the server, retry/sleep a couple times
// in case it hasn't finished starting up yet.
func getTestsList(baseURL string) (*[]controllers.TestSuiteDesc, error) {
var (
err error
resp *http.Response
testSuites []controllers.TestSuiteDesc
)
for i := 0; ; i++ {
if resp, err = http.Get(baseURL + "/@tests.list"); err == nil {
if resp.StatusCode == http.StatusOK {
break
}
}
if i < 3 {
time.Sleep(3 * time.Second)
continue
}
if err != nil {
errorf("Failed to request test list: %s", err)
} else {
errorf("Failed to request test list: non-200 response")
}
}
defer func() {
_ = resp.Body.Close()
}()
err = json.NewDecoder(resp.Body).Decode(&testSuites)
return &testSuites, err
}
func runTestSuites(baseURL, resultPath string, testSuites *[]controllers.TestSuiteDesc) (*[]controllers.TestSuiteResult, bool) {
// Load the result template, which we execute for each suite.
module, _ := revel.ModuleByName("testrunner")
TemplateLoader := revel.NewTemplateLoader([]string{filepath.Join(module.Path, "app", "views")})
if err := TemplateLoader.Refresh(); err != nil {
errorf("Failed to compile templates: %s", err)
}
resultTemplate, err := TemplateLoader.Template("TestRunner/SuiteResult.html")
if err != nil {
errorf("Failed to load suite result template: %s", err)
}
var (
overallSuccess = true
failedResults []controllers.TestSuiteResult
)
for _, suite := range *testSuites {
// Print the name of the suite we're running.
name := suite.Name
if len(name) > 22 {
name = name[:19] + "..."
}
fmt.Printf("%-22s", name)
// Run every test.
startTime := time.Now()
suiteResult := controllers.TestSuiteResult{Name: suite.Name, Passed: true}
for _, test := range suite.Tests {
testURL := baseURL + "/@tests/" + suite.Name + "/" + test.Name
resp, err := http.Get(testURL)
if err != nil {
errorf("Failed to fetch test result at url %s: %s", testURL, err)
}
defer func() {
_ = resp.Body.Close()
}()
var testResult controllers.TestResult
err = json.NewDecoder(resp.Body).Decode(&testResult)
if err == nil && !testResult.Passed {
suiteResult.Passed = false
}
suiteResult.Results = append(suiteResult.Results, testResult)
}
overallSuccess = overallSuccess && suiteResult.Passed
// Print result. (Just PASSED or FAILED, and the time taken)
suiteResultStr, suiteAlert := "PASSED", ""
if !suiteResult.Passed {
suiteResultStr, suiteAlert = "FAILED", "!"
failedResults = append(failedResults, suiteResult)
}
fmt.Printf("%8s%3s%6ds\n", suiteResultStr, suiteAlert, int(time.Since(startTime).Seconds()))
// Create the result HTML file.
suiteResultFilename := filepath.Join(resultPath,
fmt.Sprintf("%s.%s.html", suite.Name, strings.ToLower(suiteResultStr)))
suiteResultFile, err := os.Create(suiteResultFilename)
if err != nil {
errorf("Failed to create result file %s: %s", suiteResultFilename, err)
}
if err = resultTemplate.Render(suiteResultFile, suiteResult); err != nil {
errorf("Failed to render result template: %s", err)
}
}
return &failedResults, overallSuccess
}

View File

@@ -1,12 +1,16 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package main
import (
"archive/tar"
"compress/gzip"
"fmt"
"go/build"
"io"
"os"
"path"
"path/filepath"
"strings"
"text/template"
@@ -14,7 +18,7 @@ import (
"github.com/revel/revel"
)
// Use a wrapper to differentiate logged panics from unexpected ones.
// LoggedError is wrapper to differentiate logged panics from unexpected ones.
type LoggedError struct{ error }
func panicOnError(err error, msg string) {
@@ -70,7 +74,7 @@ func mustCopyDir(destDir, srcDir string, data map[string]interface{}) error {
// Get the relative path from the source base, and the corresponding path in
// the dest directory.
relSrcPath := strings.TrimLeft(srcPath[len(srcDir):], string(os.PathSeparator))
destPath := path.Join(destDir, relSrcPath)
destPath := filepath.Join(destDir, relSrcPath)
// Skip dot files and dot directories.
if strings.HasPrefix(relSrcPath, ".") {
@@ -82,7 +86,7 @@ func mustCopyDir(destDir, srcDir string, data map[string]interface{}) error {
// Create a subdirectory if necessary.
if info.IsDir() {
err := os.MkdirAll(path.Join(destDir, relSrcPath), 0777)
err := os.MkdirAll(filepath.Join(destDir, relSrcPath), 0777)
if !os.IsExist(err) {
panicOnError(err, "Failed to create directory")
}
@@ -104,22 +108,30 @@ func mustCopyDir(destDir, srcDir string, data map[string]interface{}) error {
func mustTarGzDir(destFilename, srcDir string) string {
zipFile, err := os.Create(destFilename)
panicOnError(err, "Failed to create archive")
defer zipFile.Close()
defer func() {
_ = zipFile.Close()
}()
gzipWriter := gzip.NewWriter(zipFile)
defer gzipWriter.Close()
defer func() {
_ = gzipWriter.Close()
}()
tarWriter := tar.NewWriter(gzipWriter)
defer tarWriter.Close()
defer func() {
_ = tarWriter.Close()
}()
revel.Walk(srcDir, func(srcPath string, info os.FileInfo, err error) error {
_ = revel.Walk(srcDir, func(srcPath string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
srcFile, err := os.Open(srcPath)
panicOnError(err, "Failed to read source file")
defer srcFile.Close()
defer func() {
_ = srcFile.Close()
}()
err = tarWriter.WriteHeader(&tar.Header{
Name: strings.TrimLeft(srcPath[len(srcDir):], string(os.PathSeparator)),
@@ -150,7 +162,15 @@ func empty(dirname string) bool {
if err != nil {
errorf("error opening directory: %s", err)
}
defer dir.Close()
defer func() {
_ = dir.Close()
}()
results, _ := dir.Readdir(1)
return len(results) == 0
}
func importPathFromCurrentDir() string {
pwd, _ := os.Getwd()
importPath, _ := filepath.Rel(filepath.Join(build.Default.GOPATH, "src"), pwd)
return filepath.ToSlash(importPath)
}

View File

@@ -2,6 +2,10 @@
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package main
import (