mirror of
https://github.com/kevin-DL/revel-cmd.git
synced 2026-01-12 11:05:19 +00:00
Compare commits
54 Commits
v0.13.0
...
server-eng
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18e6b92704 | ||
|
|
49041fb83d | ||
|
|
f86def601d | ||
|
|
15875dc9a1 | ||
|
|
16f98f92e0 | ||
|
|
9de11613ce | ||
|
|
e1776bda3c | ||
|
|
32d1f12b51 | ||
|
|
d114a92b3d | ||
|
|
8bf654d8b0 | ||
|
|
79ed869901 | ||
|
|
d68b27ae81 | ||
|
|
ce84b78204 | ||
|
|
19ca52182d | ||
|
|
bf30aab381 | ||
|
|
bd4663b651 | ||
|
|
b81860de5f | ||
|
|
3ba212afb4 | ||
|
|
d2b1730439 | ||
|
|
95d6366c0d | ||
|
|
0f47be728a | ||
|
|
fb1f8c2706 | ||
|
|
da79330cfb | ||
|
|
6ec49296c9 | ||
|
|
0ec369fd48 | ||
|
|
5eac8fae04 | ||
|
|
3dcee9651d | ||
|
|
6573696992 | ||
|
|
a4888fa407 | ||
|
|
8e4203838a | ||
|
|
e0aa1901b8 | ||
|
|
f6c6c931d3 | ||
|
|
8dac9acf77 | ||
|
|
e634cbfc7d | ||
|
|
adcebf9aca | ||
|
|
7b90dfa83e | ||
|
|
d865cfce90 | ||
|
|
52400dbc3d | ||
|
|
d8c5c0732f | ||
|
|
62fc677f3a | ||
|
|
0e6d8d56a2 | ||
|
|
86e9258a8f | ||
|
|
faf7e698f3 | ||
|
|
54ef57e56d | ||
|
|
612de1d3a4 | ||
|
|
28c0df2ff3 | ||
|
|
4b46dbb1a7 | ||
|
|
c18d43d25e | ||
|
|
ab1e84cf41 | ||
|
|
a5c8a8da09 | ||
|
|
5a57eaa743 | ||
|
|
514b078c3d | ||
|
|
e485de7e9c | ||
|
|
4b9e74e1ea |
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
|
||||||
@@ -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
|
package harness
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/revel/revel"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/revel/revel"
|
||||||
)
|
)
|
||||||
|
|
||||||
// App contains the configuration for running a Revel app. (Not for the app itself)
|
// 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.
|
cmd AppCmd // The last cmd returned.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewApp returns app instance with binary path in it
|
||||||
func NewApp(binPath string) *App {
|
func NewApp(binPath string) *App {
|
||||||
return &App{BinaryPath: binPath}
|
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 {
|
func (a *App) Cmd() AppCmd {
|
||||||
a.cmd = NewAppCmd(a.BinaryPath, a.Port)
|
a.cmd = NewAppCmd(a.BinaryPath, a.Port)
|
||||||
return a.cmd
|
return a.cmd
|
||||||
@@ -40,6 +46,7 @@ type AppCmd struct {
|
|||||||
*exec.Cmd
|
*exec.Cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAppCmd returns the AppCmd with parameters initialized for running app
|
||||||
func NewAppCmd(binPath string, port int) AppCmd {
|
func NewAppCmd(binPath string, port int) AppCmd {
|
||||||
cmd := exec.Command(binPath,
|
cmd := exec.Command(binPath,
|
||||||
fmt.Sprintf("-port=%d", port),
|
fmt.Sprintf("-port=%d", port),
|
||||||
@@ -69,6 +76,8 @@ func (cmd AppCmd) Start() error {
|
|||||||
case <-listeningWriter.notifyReady:
|
case <-listeningWriter.notifyReady:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO remove this unreachable code and document it
|
||||||
panic("Impossible")
|
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() {
|
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.TRACE.Println("Killing revel server pid", cmd.Process.Pid)
|
||||||
@@ -95,7 +104,7 @@ func (cmd AppCmd) Kill() {
|
|||||||
func (cmd AppCmd) waitChan() <-chan struct{} {
|
func (cmd AppCmd) waitChan() <-chan struct{} {
|
||||||
ch := make(chan struct{}, 1)
|
ch := make(chan struct{}, 1)
|
||||||
go func() {
|
go func() {
|
||||||
cmd.Wait()
|
_ = cmd.Wait()
|
||||||
ch <- struct{}{}
|
ch <- struct{}{}
|
||||||
}()
|
}()
|
||||||
return ch
|
return ch
|
||||||
|
|||||||
@@ -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
|
package harness
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -12,6 +16,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
)
|
)
|
||||||
@@ -44,8 +49,8 @@ func Build(buildFlags ...string) (app *App, compileError *revel.Error) {
|
|||||||
"ImportPaths": calcImportAliases(sourceInfo),
|
"ImportPaths": calcImportAliases(sourceInfo),
|
||||||
"TestSuites": sourceInfo.TestSuites(),
|
"TestSuites": sourceInfo.TestSuites(),
|
||||||
}
|
}
|
||||||
genSource("tmp", "main.go", MAIN, templateArgs)
|
genSource("tmp", "main.go", RevelMainTemplate, templateArgs)
|
||||||
genSource("routes", "routes.go", ROUTES, templateArgs)
|
genSource("routes", "routes.go", RevelRoutesTemplate, templateArgs)
|
||||||
|
|
||||||
// Read build config.
|
// Read build config.
|
||||||
buildTags := revel.Config.StringDefault("build.tags", "")
|
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.
|
// 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
|
// Change binary path for Windows build
|
||||||
goos := runtime.GOOS
|
goos := runtime.GOOS
|
||||||
@@ -77,7 +82,18 @@ func Build(buildFlags ...string) (app *App, compileError *revel.Error) {
|
|||||||
gotten := make(map[string]struct{})
|
gotten := make(map[string]struct{})
|
||||||
for {
|
for {
|
||||||
appVersion := getAppVersion()
|
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{
|
flags := []string{
|
||||||
"build",
|
"build",
|
||||||
"-i",
|
"-i",
|
||||||
@@ -88,7 +104,8 @@ func Build(buildFlags ...string) (app *App, compileError *revel.Error) {
|
|||||||
// Add in build flags
|
// Add in build flags
|
||||||
flags = append(flags, buildFlags...)
|
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"))
|
flags = append(flags, path.Join(revel.ImportPath, "app", "tmp"))
|
||||||
|
|
||||||
buildCmd := exec.Command(goPath, flags...)
|
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.
|
// Success getting the import, attempt to build again.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO remove this unreachable code and document it
|
||||||
revel.ERROR.Fatalf("Not reachable")
|
revel.ERROR.Fatalf("Not reachable")
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@@ -143,7 +162,7 @@ func getAppVersion() string {
|
|||||||
// Check for the git binary
|
// Check for the git binary
|
||||||
if gitPath, err := exec.LookPath("git"); err == nil {
|
if gitPath, err := exec.LookPath("git"); err == nil {
|
||||||
// Check for the .git directory
|
// Check for the .git directory
|
||||||
gitDir := path.Join(revel.BasePath, ".git")
|
gitDir := filepath.Join(revel.BasePath, ".git")
|
||||||
info, err := os.Stat(gitDir)
|
info, err := os.Stat(gitDir)
|
||||||
if (err != nil && os.IsNotExist(err)) || !info.IsDir() {
|
if (err != nil && os.IsNotExist(err)) || !info.IsDir() {
|
||||||
return ""
|
return ""
|
||||||
@@ -171,14 +190,17 @@ func cleanSource(dirs ...string) {
|
|||||||
|
|
||||||
func cleanDir(dir string) {
|
func cleanDir(dir string) {
|
||||||
revel.INFO.Println("Cleaning dir " + dir)
|
revel.INFO.Println("Cleaning dir " + dir)
|
||||||
tmpPath := path.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.ERROR.Println("Failed to clean dir:", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
defer f.Close()
|
defer func() {
|
||||||
|
_ = f.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
infos, err := f.Readdir(0)
|
infos, err := f.Readdir(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !os.IsNotExist(err) {
|
if !os.IsNotExist(err) {
|
||||||
@@ -186,7 +208,7 @@ func cleanDir(dir string) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, info := range infos {
|
for _, info := range infos {
|
||||||
path := path.Join(tmpPath, info.Name())
|
path := filepath.Join(tmpPath, info.Name())
|
||||||
if info.IsDir() {
|
if info.IsDir() {
|
||||||
err := os.RemoveAll(path)
|
err := os.RemoveAll(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -212,20 +234,22 @@ func genSource(dir, filename, templateSource string, args map[string]interface{}
|
|||||||
|
|
||||||
// Create a fresh dir.
|
// Create a fresh dir.
|
||||||
cleanSource(dir)
|
cleanSource(dir)
|
||||||
tmpPath := path.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.ERROR.Fatalf("Failed to make '%v' directory: %v", dir, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the file
|
// Create the file
|
||||||
file, err := os.Create(path.Join(tmpPath, filename))
|
file, err := os.Create(filepath.Join(tmpPath, filename))
|
||||||
defer file.Close()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
revel.ERROR.Fatalf("Failed to create file: %v", err)
|
revel.ERROR.Fatalf("Failed to create file: %v", err)
|
||||||
}
|
}
|
||||||
_, err = file.WriteString(sourceCode)
|
defer func() {
|
||||||
if err != nil {
|
_ = file.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
if _, err = file.WriteString(sourceCode); err != nil {
|
||||||
revel.ERROR.Fatalf("Failed to write to file: %v", err)
|
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) {
|
func addAlias(aliases map[string]string, importPath, pkgName string) {
|
||||||
alias, ok := aliases[importPath]
|
alias, ok := aliases[importPath]
|
||||||
if ok {
|
if ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -274,7 +298,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) {
|
for containsValue(aliases, alias) || alias=="revel" {
|
||||||
alias = fmt.Sprintf("%s%d", pkgName, i)
|
alias = fmt.Sprintf("%s%d", pkgName, i)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
@@ -344,7 +368,8 @@ func newCompileError(output []byte) *revel.Error {
|
|||||||
return compileError
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -398,7 +423,9 @@ func main() {
|
|||||||
revel.Run(*port)
|
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
|
package routes
|
||||||
|
|
||||||
import "github.com/revel/revel"
|
import "github.com/revel/revel"
|
||||||
@@ -414,7 +441,7 @@ func (_ t{{$c.StructName}}) {{.Name}}({{range .Args}}
|
|||||||
args := make(map[string]string)
|
args := make(map[string]string)
|
||||||
{{range .Args}}
|
{{range .Args}}
|
||||||
revel.Unbind(args, "{{.Name}}", {{.Name}}){{end}}
|
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}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
@@ -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
|
// 1. Parse the user program, generating a main.go file that registers
|
||||||
// controller classes and starts the user's server.
|
// controller classes and starts the user's server.
|
||||||
// 2. Build and run the user program. Show compile errors.
|
// 2. Build and run the user program. Show compile errors.
|
||||||
// 3. Monitor the user source and re-build / restart the program when necessary.
|
// 3. Monitor the user source and re-build / restart the program when necessary.
|
||||||
//
|
//
|
||||||
// Source files are generated in the app/tmp directory.
|
// Source files are generated in the app/tmp directory.
|
||||||
|
|
||||||
package harness
|
package harness
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -44,10 +47,12 @@ type Harness struct {
|
|||||||
proxy *httputil.ReverseProxy
|
proxy *httputil.ReverseProxy
|
||||||
}
|
}
|
||||||
|
|
||||||
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.
|
||||||
@@ -84,12 +89,14 @@ func NewHarness() *Harness {
|
|||||||
// Prefer the app's views/errors directory, and fall back to the stock error pages.
|
// Prefer the app's views/errors directory, and fall back to the stock error pages.
|
||||||
revel.MainTemplateLoader = revel.NewTemplateLoader(
|
revel.MainTemplateLoader = revel.NewTemplateLoader(
|
||||||
[]string{filepath.Join(revel.RevelPath, "templates")})
|
[]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)
|
port := revel.Config.IntDefault("harness.port", 0)
|
||||||
scheme := "http"
|
scheme := "http"
|
||||||
if revel.HttpSsl {
|
if revel.HTTPSsl {
|
||||||
scheme = "https"
|
scheme = "https"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +117,7 @@ func NewHarness() *Harness {
|
|||||||
proxy: httputil.NewSingleHostReverseProxy(serverURL),
|
proxy: httputil.NewSingleHostReverseProxy(serverURL),
|
||||||
}
|
}
|
||||||
|
|
||||||
if revel.HttpSsl {
|
if revel.HTTPSsl {
|
||||||
harness.proxy.Transport = &http.Transport{
|
harness.proxy.Transport = &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
}
|
}
|
||||||
@@ -166,13 +173,16 @@ func (h *Harness) Run() {
|
|||||||
watcher.Listen(h, paths...)
|
watcher.Listen(h, paths...)
|
||||||
|
|
||||||
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.INFO.Printf("Listening on %s", addr)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if revel.HttpSsl {
|
if revel.HTTPSsl {
|
||||||
err = http.ListenAndServeTLS(addr, revel.HttpSslCert,
|
err = http.ListenAndServeTLS(
|
||||||
revel.HttpSslKey, h)
|
addr,
|
||||||
|
revel.HTTPSslCert,
|
||||||
|
revel.HTTPSslKey,
|
||||||
|
h)
|
||||||
} else {
|
} else {
|
||||||
err = http.ListenAndServe(addr, h)
|
err = http.ListenAndServe(addr, h)
|
||||||
}
|
}
|
||||||
@@ -213,7 +223,7 @@ func proxyWebsocket(w http.ResponseWriter, r *http.Request, host string) {
|
|||||||
d net.Conn
|
d net.Conn
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
if revel.HttpSsl {
|
if revel.HTTPSsl {
|
||||||
// since this proxy isn't used in production,
|
// since this proxy isn't used in production,
|
||||||
// it's OK to set InsecureSkipVerify to true
|
// it's OK to set InsecureSkipVerify to true
|
||||||
// no need to add another configuration option.
|
// no need to add another configuration option.
|
||||||
@@ -236,8 +246,14 @@ func proxyWebsocket(w http.ResponseWriter, r *http.Request, host string) {
|
|||||||
revel.ERROR.Printf("Hijack error: %v", err)
|
revel.ERROR.Printf("Hijack error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer nc.Close()
|
defer func() {
|
||||||
defer d.Close()
|
if err = nc.Close(); err != nil {
|
||||||
|
revel.ERROR.Println(err)
|
||||||
|
}
|
||||||
|
if err = d.Close(); err != nil {
|
||||||
|
revel.ERROR.Println(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
err = r.Write(d)
|
err = r.Write(d)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -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
|
package harness
|
||||||
|
|
||||||
// This file handles the app code introspection.
|
// This file handles the app code introspection.
|
||||||
@@ -25,7 +29,7 @@ type SourceInfo struct {
|
|||||||
StructSpecs []*TypeInfo
|
StructSpecs []*TypeInfo
|
||||||
// ValidationKeys provides a two-level lookup. The keys are:
|
// ValidationKeys provides a two-level lookup. The keys are:
|
||||||
// 1. The fully-qualified function name,
|
// 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.
|
// 2. Within that func's file, the line number of the (overall) expression statement.
|
||||||
// e.g. the line returned from runtime.Caller()
|
// e.g. the line returned from runtime.Caller()
|
||||||
// The result of the lookup the name of variable being validated.
|
// 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.
|
// TypeInfo summarizes information about a struct type in the app source code.
|
||||||
type TypeInfo struct {
|
type TypeInfo struct {
|
||||||
StructName string // e.g. "Application"
|
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"
|
PackageName string // e.g. "controllers"
|
||||||
MethodSpecs []*MethodSpec
|
MethodSpecs []*MethodSpec
|
||||||
|
|
||||||
@@ -60,12 +64,14 @@ type methodCall struct {
|
|||||||
Names []string
|
Names []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MethodSpec holds the information of one Method
|
||||||
type MethodSpec struct {
|
type MethodSpec struct {
|
||||||
Name string // Name of the method, e.g. "Index"
|
Name string // Name of the method, e.g. "Index"
|
||||||
Args []*MethodArg // Argument descriptors
|
Args []*MethodArg // Argument descriptors
|
||||||
RenderCalls []*methodCall // Descriptions of Render() invocations from this Method.
|
RenderCalls []*methodCall // Descriptions of Render() invocations from this Method.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MethodArg holds the information of one argument
|
||||||
type MethodArg struct {
|
type MethodArg struct {
|
||||||
Name string // Name of the argument.
|
Name string // Name of the argument.
|
||||||
TypeExpr TypeExpr // The name of the type, e.g. "int", "*pkg.UserType"
|
TypeExpr TypeExpr // The name of the type, e.g. "int", "*pkg.UserType"
|
||||||
@@ -80,8 +86,9 @@ type embeddedTypeName struct {
|
|||||||
// receiver.
|
// receiver.
|
||||||
type methodMap map[string][]*MethodSpec
|
type methodMap map[string][]*MethodSpec
|
||||||
|
|
||||||
// Parse the app controllers directory and return a list of the controller types found.
|
// ProcessSource parses the app controllers directory and
|
||||||
// Returns a CompileError if the parsing fails.
|
// returns a list of the controller types found.
|
||||||
|
// Otherwise CompileError if the parsing fails.
|
||||||
func ProcessSource(roots []string) (*SourceInfo, *revel.Error) {
|
func ProcessSource(roots []string) (*SourceInfo, *revel.Error) {
|
||||||
var (
|
var (
|
||||||
srcInfo *SourceInfo
|
srcInfo *SourceInfo
|
||||||
@@ -120,7 +127,7 @@ func ProcessSource(roots []string) (*SourceInfo, *revel.Error) {
|
|||||||
}, 0)
|
}, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errList, ok := err.(scanner.ErrorList); ok {
|
if errList, ok := err.(scanner.ErrorList); ok {
|
||||||
var pos token.Position = errList[0].Pos
|
var pos = errList[0].Pos
|
||||||
compileError = &revel.Error{
|
compileError = &revel.Error{
|
||||||
SourceType: ".go source",
|
SourceType: ".go source",
|
||||||
Title: "Go Compilation Error",
|
Title: "Go Compilation Error",
|
||||||
@@ -139,6 +146,8 @@ func ProcessSource(roots []string) (*SourceInfo, *revel.Error) {
|
|||||||
|
|
||||||
return compileError
|
return compileError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
log.Fatalf("Failed to parse dir: %s", err)
|
||||||
}
|
}
|
||||||
@@ -151,8 +160,20 @@ 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 {
|
||||||
|
for i := range pkgs {
|
||||||
|
println("Found package ", i)
|
||||||
|
}
|
||||||
log.Println("Most unexpected! Multiple packages in a single directory:", pkgs)
|
log.Println("Most unexpected! Multiple packages in a single directory:", pkgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,7 +440,7 @@ func appendAction(fset *token.FileSet, mm methodMap, decl ast.Decl, pkgImportPat
|
|||||||
if selExpr.Sel.Name != "Result" {
|
if selExpr.Sel.Name != "Result" {
|
||||||
return
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,7 +511,7 @@ func appendAction(fset *token.FileSet, mm methodMap, decl ast.Decl, pkgImportPat
|
|||||||
})
|
})
|
||||||
|
|
||||||
var recvTypeName string
|
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 {
|
if recvStarType, ok := recvType.(*ast.StarExpr); ok {
|
||||||
recvTypeName = recvStarType.X.(*ast.Ident).Name
|
recvTypeName = recvStarType.X.(*ast.Ident).Name
|
||||||
} else {
|
} else {
|
||||||
@@ -597,7 +618,7 @@ func getValidationParameter(funcDecl *ast.FuncDecl, imports map[string]string) *
|
|||||||
continue
|
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
|
return field.Names[0].Obj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -673,16 +694,20 @@ func (s *SourceInfo) TypesThatEmbed(targetType string) (filtered []*TypeInfo) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ControllerSpecs returns the all the contollers that embeds
|
||||||
|
// `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.REVEL_IMPORT_PATH + ".Controller")
|
s.controllerSpecs = s.TypesThatEmbed(revel.RevelImportPath + ".Controller")
|
||||||
}
|
}
|
||||||
return s.controllerSpecs
|
return s.controllerSpecs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestSuites returns the all the Application tests that embeds
|
||||||
|
// `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.REVEL_IMPORT_PATH + "/testing.TestSuite")
|
s.testSuites = s.TypesThatEmbed(revel.RevelImportPath + "/testing.TestSuite")
|
||||||
}
|
}
|
||||||
return s.testSuites
|
return s.testSuites
|
||||||
}
|
}
|
||||||
@@ -705,7 +730,7 @@ func (e TypeExpr) TypeName(pkgOverride string) string {
|
|||||||
return e.Expr[:e.pkgIndex] + pkgName + "." + e.Expr[e.pkgIndex:]
|
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 {
|
func NewTypeExpr(pkgName string, expr ast.Expr) TypeExpr {
|
||||||
switch t := expr.(type) {
|
switch t := expr.(type) {
|
||||||
case *ast.Ident:
|
case *ast.Ident:
|
||||||
@@ -731,35 +756,40 @@ func NewTypeExpr(pkgName string, expr ast.Expr) TypeExpr {
|
|||||||
return TypeExpr{Valid: false}
|
return TypeExpr{Valid: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
var _BUILTIN_TYPES = map[string]struct{}{
|
var builtInTypes = map[string]struct{}{
|
||||||
"bool": struct{}{},
|
"bool": {},
|
||||||
"byte": struct{}{},
|
"byte": {},
|
||||||
"complex128": struct{}{},
|
"complex128": {},
|
||||||
"complex64": struct{}{},
|
"complex64": {},
|
||||||
"error": struct{}{},
|
"error": {},
|
||||||
"float32": struct{}{},
|
"float32": {},
|
||||||
"float64": struct{}{},
|
"float64": {},
|
||||||
"int": struct{}{},
|
"int": {},
|
||||||
"int16": struct{}{},
|
"int16": {},
|
||||||
"int32": struct{}{},
|
"int32": {},
|
||||||
"int64": struct{}{},
|
"int64": {},
|
||||||
"int8": struct{}{},
|
"int8": {},
|
||||||
"rune": struct{}{},
|
"rune": {},
|
||||||
"string": struct{}{},
|
"string": {},
|
||||||
"uint": struct{}{},
|
"uint": {},
|
||||||
"uint16": struct{}{},
|
"uint16": {},
|
||||||
"uint32": struct{}{},
|
"uint32": {},
|
||||||
"uint64": struct{}{},
|
"uint64": {},
|
||||||
"uint8": struct{}{},
|
"uint8": {},
|
||||||
"uintptr": struct{}{},
|
"uintptr": {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsBuiltinType checks the given type is built-in types of Go
|
||||||
func IsBuiltinType(name string) bool {
|
func IsBuiltinType(name string) bool {
|
||||||
_, ok := _BUILTIN_TYPES[name]
|
_, ok := builtInTypes[name]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func importPathFromPath(root string) string {
|
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) {
|
for _, gopath := range filepath.SplitList(build.Default.GOPATH) {
|
||||||
srcPath := filepath.Join(gopath, "src")
|
srcPath := filepath.Join(gopath, "src")
|
||||||
if strings.HasPrefix(root, srcPath) {
|
if strings.HasPrefix(root, srcPath) {
|
||||||
|
|||||||
@@ -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
|
package harness
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/revel/revel"
|
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
@@ -10,6 +13,8 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/revel/revel"
|
||||||
)
|
)
|
||||||
|
|
||||||
const validationKeysSource = `
|
const validationKeysSource = `
|
||||||
@@ -77,7 +82,7 @@ func TestGetValidationKeys(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, decl := range file.Decls {
|
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] {
|
for k, v := range expectedValidationKeys[i] {
|
||||||
if lineKeys[k] != v {
|
if lineKeys[k] != v {
|
||||||
t.Errorf("Not found - %d: %v - Actual Map: %v", k, v, lineKeys)
|
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{
|
var TypeExprs = map[string]TypeExpr{
|
||||||
"int": TypeExpr{"int", "", 0, true},
|
"int": {"int", "", 0, true},
|
||||||
"*int": TypeExpr{"*int", "", 1, true},
|
"*int": {"*int", "", 1, true},
|
||||||
"[]int": TypeExpr{"[]int", "", 2, true},
|
"[]int": {"[]int", "", 2, true},
|
||||||
"...int": TypeExpr{"[]int", "", 2, true},
|
"...int": {"[]int", "", 2, true},
|
||||||
"[]*int": TypeExpr{"[]*int", "", 3, true},
|
"[]*int": {"[]*int", "", 3, true},
|
||||||
"...*int": TypeExpr{"[]*int", "", 3, true},
|
"...*int": {"[]*int", "", 3, true},
|
||||||
"MyType": TypeExpr{"MyType", "pkg", 0, true},
|
"MyType": {"MyType", "pkg", 0, true},
|
||||||
"*MyType": TypeExpr{"*MyType", "pkg", 1, true},
|
"*MyType": {"*MyType", "pkg", 1, true},
|
||||||
"[]MyType": TypeExpr{"[]MyType", "pkg", 2, true},
|
"[]MyType": {"[]MyType", "pkg", 2, true},
|
||||||
"...MyType": TypeExpr{"[]MyType", "pkg", 2, true},
|
"...MyType": {"[]MyType", "pkg", 2, true},
|
||||||
"[]*MyType": TypeExpr{"[]*MyType", "pkg", 3, true},
|
"[]*MyType": {"[]*MyType", "pkg", 3, true},
|
||||||
"...*MyType": TypeExpr{"[]*MyType", "pkg", 3, true},
|
"...*MyType": {"[]*MyType", "pkg", 3, true},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTypeExpr(t *testing.T) {
|
func TestTypeExpr(t *testing.T) {
|
||||||
@@ -125,10 +130,10 @@ func TestTypeExpr(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if array {
|
if array {
|
||||||
expr = &ast.ArrayType{expr.Pos(), nil, expr}
|
expr = &ast.ArrayType{Lbrack: expr.Pos(), Len: nil, Elt: expr}
|
||||||
}
|
}
|
||||||
if ellipsis {
|
if ellipsis {
|
||||||
expr = &ast.Ellipsis{expr.Pos(), expr}
|
expr = &ast.Ellipsis{Ellipsis: expr.Pos(), Elt: expr}
|
||||||
}
|
}
|
||||||
|
|
||||||
actual := NewTypeExpr("pkg", expr)
|
actual := NewTypeExpr("pkg", expr)
|
||||||
@@ -139,17 +144,17 @@ func TestTypeExpr(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessBookingSource(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})
|
sourceInfo, err := ProcessSource([]string{revel.AppPath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Failed to process booking source with error:", err)
|
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{
|
expectedControllerSpecs := []*TypeInfo{
|
||||||
{"GorpController", CONTROLLER_PKG, "controllers", nil, nil},
|
{"GorpController", controllerPackage, "controllers", nil, nil},
|
||||||
{"Application", CONTROLLER_PKG, "controllers", nil, nil},
|
{"Application", controllerPackage, "controllers", nil, nil},
|
||||||
{"Hotels", CONTROLLER_PKG, "controllers", nil, nil},
|
{"Hotels", controllerPackage, "controllers", nil, nil},
|
||||||
}
|
}
|
||||||
if len(sourceInfo.ControllerSpecs()) != len(expectedControllerSpecs) {
|
if len(sourceInfo.ControllerSpecs()) != len(expectedControllerSpecs) {
|
||||||
t.Errorf("Unexpected number of controllers found. Expected %d, Found %d",
|
t.Errorf("Unexpected number of controllers found. Expected %d, Found %d",
|
||||||
@@ -177,7 +182,7 @@ NEXT_TEST:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkProcessBookingSource(b *testing.B) {
|
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)
|
revel.TRACE = log.New(ioutil.Discard, "", 0)
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -27,7 +30,7 @@ WARNING: The target path will be completely deleted, if it already exists!
|
|||||||
|
|
||||||
For example:
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
appImportPath, destPath, mode := args[0], args[1], "dev"
|
appImportPath, destPath, mode := args[0], args[1], DefaultRunMode
|
||||||
if len(args) >= 3 {
|
if len(args) >= 3 {
|
||||||
mode = args[2]
|
mode = args[2]
|
||||||
}
|
}
|
||||||
@@ -52,12 +55,17 @@ func buildApp(args []string) {
|
|||||||
|
|
||||||
// First, verify that it is either already empty or looks like a previous
|
// First, verify that it is either already empty or looks like a previous
|
||||||
// build (to avoid clobbering anything)
|
// 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)
|
errorf("Abort: %s exists and does not look like a build directory.", destPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
os.RemoveAll(destPath)
|
if err := os.RemoveAll(destPath); err != nil && !os.IsNotExist(err) {
|
||||||
os.MkdirAll(destPath, 0777)
|
revel.ERROR.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll(destPath, 0777); err != nil {
|
||||||
|
revel.ERROR.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
app, reverr := harness.Build()
|
app, reverr := harness.Build()
|
||||||
panicOnError(reverr, "Failed to build")
|
panicOnError(reverr, "Failed to build")
|
||||||
@@ -69,14 +77,14 @@ func buildApp(args []string) {
|
|||||||
// - app
|
// - app
|
||||||
|
|
||||||
// Revel and the app are in a directory structure mirroring import path
|
// Revel and the app are in a directory structure mirroring import path
|
||||||
srcPath := path.Join(destPath, "src")
|
srcPath := filepath.Join(destPath, "src")
|
||||||
destBinaryPath := path.Join(destPath, filepath.Base(app.BinaryPath))
|
destBinaryPath := filepath.Join(destPath, filepath.Base(app.BinaryPath))
|
||||||
tmpRevelPath := path.Join(srcPath, filepath.FromSlash(revel.REVEL_IMPORT_PATH))
|
tmpRevelPath := filepath.Join(srcPath, filepath.FromSlash(revel.RevelImportPath))
|
||||||
mustCopyFile(destBinaryPath, app.BinaryPath)
|
mustCopyFile(destBinaryPath, app.BinaryPath)
|
||||||
mustChmod(destBinaryPath, 0755)
|
mustChmod(destBinaryPath, 0755)
|
||||||
mustCopyDir(path.Join(tmpRevelPath, "conf"), path.Join(revel.RevelPath, "conf"), nil)
|
_ = mustCopyDir(filepath.Join(tmpRevelPath, "conf"), filepath.Join(revel.RevelPath, "conf"), nil)
|
||||||
mustCopyDir(path.Join(tmpRevelPath, "templates"), path.Join(revel.RevelPath, "templates"), nil)
|
_ = mustCopyDir(filepath.Join(tmpRevelPath, "templates"), filepath.Join(revel.RevelPath, "templates"), nil)
|
||||||
mustCopyDir(path.Join(srcPath, filepath.FromSlash(appImportPath)), revel.BasePath, nil)
|
_ = mustCopyDir(filepath.Join(srcPath, filepath.FromSlash(appImportPath)), revel.BasePath, nil)
|
||||||
|
|
||||||
// Find all the modules used and copy them over.
|
// Find all the modules used and copy them over.
|
||||||
config := revel.Config.Raw()
|
config := revel.Config.Raw()
|
||||||
@@ -99,14 +107,14 @@ func buildApp(args []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for importPath, fsPath := range modulePaths {
|
for importPath, fsPath := range modulePaths {
|
||||||
mustCopyDir(path.Join(srcPath, importPath), fsPath, nil)
|
_ = mustCopyDir(filepath.Join(srcPath, importPath), fsPath, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
tmplData, runShPath := map[string]interface{}{
|
tmplData, runShPath := map[string]interface{}{
|
||||||
"BinName": filepath.Base(app.BinaryPath),
|
"BinName": filepath.Base(app.BinaryPath),
|
||||||
"ImportPath": appImportPath,
|
"ImportPath": appImportPath,
|
||||||
"Mode": mode,
|
"Mode": mode,
|
||||||
}, path.Join(destPath, "run.sh")
|
}, filepath.Join(destPath, "run.sh")
|
||||||
|
|
||||||
mustRenderTemplate(
|
mustRenderTemplate(
|
||||||
runShPath,
|
runShPath,
|
||||||
|
|||||||
@@ -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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/build"
|
"go/build"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
var cmdClean = &Command{
|
var cmdClean = &Command{
|
||||||
@@ -15,7 +19,7 @@ Clean the Revel web application named by the given import path.
|
|||||||
|
|
||||||
For example:
|
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.
|
It removes the app/tmp and app/routes directory.
|
||||||
`,
|
`,
|
||||||
@@ -38,8 +42,8 @@ func cleanApp(args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
purgeDirs := []string{
|
purgeDirs := []string{
|
||||||
path.Join(appPkg.Dir, "app", "tmp"),
|
filepath.Join(appPkg.Dir, "app", "tmp"),
|
||||||
path.Join(appPkg.Dir, "app", "routes"),
|
filepath.Join(appPkg.Dir, "app", "routes"),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dir := range purgeDirs {
|
for _, dir := range purgeDirs {
|
||||||
|
|||||||
16
revel/new.go
16
revel/new.go
@@ -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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -46,6 +50,7 @@ var (
|
|||||||
|
|
||||||
// revel related paths
|
// revel related paths
|
||||||
revelPkg *build.Package
|
revelPkg *build.Package
|
||||||
|
revelCmdPkg *build.Package
|
||||||
appPath string
|
appPath string
|
||||||
appName string
|
appName string
|
||||||
basePath string
|
basePath string
|
||||||
@@ -148,7 +153,7 @@ func setApplicationPath(args []string) {
|
|||||||
errorf("Abort: Import path %s already exists.\n", importPath)
|
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 {
|
if err != nil {
|
||||||
errorf("Abort: Could not find Revel source code: %s\n", err)
|
errorf("Abort: Could not find Revel source code: %s\n", err)
|
||||||
}
|
}
|
||||||
@@ -190,7 +195,12 @@ func setSkeletonPath(args []string) {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
// use the revel default
|
// 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)
|
err = os.MkdirAll(appPath, 0777)
|
||||||
panicOnError(err, "Failed to create directory "+appPath)
|
panicOnError(err, "Failed to create directory "+appPath)
|
||||||
|
|
||||||
mustCopyDir(appPath, skeletonPath, map[string]interface{}{
|
_ = mustCopyDir(appPath, skeletonPath, map[string]interface{}{
|
||||||
// app.conf
|
// app.conf
|
||||||
"AppName": appName,
|
"AppName": appName,
|
||||||
"BasePath": basePath,
|
"BasePath": basePath,
|
||||||
|
|||||||
@@ -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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -23,7 +27,7 @@ Run mode defaults to "dev".
|
|||||||
|
|
||||||
For example:
|
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.
|
// Determine the run mode.
|
||||||
mode := "dev"
|
mode := DefaultRunMode
|
||||||
if len(args) >= 2 {
|
if len(args) >= 2 {
|
||||||
mode = args[1]
|
mode = args[1]
|
||||||
}
|
}
|
||||||
@@ -48,7 +52,9 @@ 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"
|
||||||
os.Remove(destFile)
|
if err := os.Remove(destFile); err != nil && !os.IsNotExist(err) {
|
||||||
|
revel.ERROR.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Collect stuff in a temp directory.
|
// Collect stuff in a temp directory.
|
||||||
tmpDir, err := ioutil.TempDir("", filepath.Base(revel.BasePath))
|
tmpDir, err := ioutil.TempDir("", filepath.Base(revel.BasePath))
|
||||||
|
|||||||
13
revel/rev.go
13
revel/rev.go
@@ -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.
|
// The command line tool for running Revel apps.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@@ -15,12 +19,21 @@ import (
|
|||||||
"github.com/agtorre/gocolorize"
|
"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.
|
// Command structure cribbed from the genius organization of the "go" command.
|
||||||
type Command struct {
|
type Command struct {
|
||||||
Run func(args []string)
|
Run func(args []string)
|
||||||
UsageLine, Short, Long string
|
UsageLine, Short, Long string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Name returns command name from usage line
|
||||||
func (cmd *Command) Name() string {
|
func (cmd *Command) Name() string {
|
||||||
name := cmd.UsageLine
|
name := cmd.UsageLine
|
||||||
i := strings.Index(name, " ")
|
i := strings.Index(name, " ")
|
||||||
|
|||||||
117
revel/run.go
117
revel/run.go
@@ -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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"go/build"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/revel/cmd/harness"
|
"github.com/revel/cmd/harness"
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
"strconv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var cmdRun = &Command{
|
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:
|
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
|
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.
|
apply and may be used to determine logic in the application itself.
|
||||||
@@ -23,44 +29,105 @@ Run mode defaults to "dev".
|
|||||||
|
|
||||||
You can set a port as an optional third parameter. For example:
|
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() {
|
func init() {
|
||||||
cmdRun.Run = runApp
|
cmdRun.Run = runApp
|
||||||
}
|
}
|
||||||
|
|
||||||
func runApp(args []string) {
|
func parseRunArgs(args []string) *RunArgs {
|
||||||
if len(args) == 0 {
|
inputArgs := RunArgs{
|
||||||
errorf("No import path given.\nRun 'revel help run' for usage.\n")
|
ImportPath: importPathFromCurrentDir(),
|
||||||
|
Mode: DefaultRunMode,
|
||||||
|
Port: revel.HTTPPort,
|
||||||
}
|
}
|
||||||
|
switch len(args) {
|
||||||
// Determine the run mode.
|
case 3:
|
||||||
mode := "dev"
|
// Possibile combinations
|
||||||
if len(args) >= 2 {
|
// revel run [import-path] [run-mode] [port]
|
||||||
mode = args[1]
|
port, err := strconv.Atoi(args[2])
|
||||||
}
|
if err != nil {
|
||||||
|
|
||||||
// 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 {
|
|
||||||
errorf("Failed to parse port as integer: %s", args[2])
|
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]
|
||||||
|
_, err := build.Import(args[0], "", build.FindOnly)
|
||||||
|
if err != nil {
|
||||||
|
revel.WARN.Printf("Unable to run using an import path, assuming import path is working directory %s %s", args[0], err.Error())
|
||||||
|
}
|
||||||
|
println("Trying to build with", args[0], err)
|
||||||
|
if 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)
|
revel.TRACE.Println("Base 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.TRACE.Println("Running in watched mode.")
|
||||||
revel.HttpPort = port
|
revel.HTTPPort = runArgs.Port
|
||||||
harness.NewHarness().Run() // Never returns.
|
harness.NewHarness().Run() // Never returns.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,6 +137,6 @@ func runApp(args []string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
errorf("Failed to build app: %s", err)
|
errorf("Failed to build app: %s", err)
|
||||||
}
|
}
|
||||||
app.Port = port
|
app.Port = runArgs.Port
|
||||||
app.Cmd().Run()
|
app.Cmd().Run()
|
||||||
}
|
}
|
||||||
|
|||||||
3
revel/skeleton/.gitignore
vendored
Normal file
3
revel/skeleton/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
test-results/
|
||||||
|
tmp/
|
||||||
|
routes/
|
||||||
43
revel/skeleton/README.md
Normal file
43
revel/skeleton/README.md
Normal 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).
|
||||||
|
|
||||||
13
revel/skeleton/app/controllers/app.go
Normal file
13
revel/skeleton/app/controllers/app.go
Normal 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()
|
||||||
|
}
|
||||||
58
revel/skeleton/app/init.go
Normal file
58
revel/skeleton/app/init.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
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.SetHttpHeader("X-Frame-Options", "SAMEORIGIN")
|
||||||
|
c.Response.SetHttpHeader("X-XSS-Protection", "1; mode=block")
|
||||||
|
c.Response.SetHttpHeader("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
|
||||||
|
// }
|
||||||
|
//}
|
||||||
21
revel/skeleton/app/views/App/Index.html
Normal file
21
revel/skeleton/app/views/App/Index.html
Normal 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" .}}
|
||||||
64
revel/skeleton/app/views/debug.html
Normal file
64
revel/skeleton/app/views/debug.html
Normal 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>
|
||||||
20
revel/skeleton/app/views/errors/404.html
Normal file
20
revel/skeleton/app/views/errors/404.html
Normal 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>
|
||||||
16
revel/skeleton/app/views/errors/500.html
Normal file
16
revel/skeleton/app/views/errors/500.html
Normal 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>
|
||||||
18
revel/skeleton/app/views/flash.html
Normal file
18
revel/skeleton/app/views/flash.html
Normal 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}}
|
||||||
5
revel/skeleton/app/views/footer.html
Normal file
5
revel/skeleton/app/views/footer.html
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{{if eq .RunMode "dev"}}
|
||||||
|
{{template "debug.html" .}}
|
||||||
|
{{end}}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
19
revel/skeleton/app/views/header.html
Normal file
19
revel/skeleton/app/views/header.html
Normal 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>
|
||||||
258
revel/skeleton/conf/app.conf.template
Normal file
258
revel/skeleton/conf/app.conf.template
Normal 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
|
||||||
19
revel/skeleton/conf/routes
Normal file
19
revel/skeleton/conf/routes
Normal 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
|
||||||
7
revel/skeleton/messages/sample.en
Normal file
7
revel/skeleton/messages/sample.en
Normal 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
|
||||||
|
|
||||||
5
revel/skeleton/public/css/bootstrap-3.3.6.min.css
vendored
Normal file
5
revel/skeleton/public/css/bootstrap-3.3.6.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
revel/skeleton/public/fonts/glyphicons-halflings-regular.ttf
Normal file
BIN
revel/skeleton/public/fonts/glyphicons-halflings-regular.ttf
Normal file
Binary file not shown.
BIN
revel/skeleton/public/fonts/glyphicons-halflings-regular.woff
Normal file
BIN
revel/skeleton/public/fonts/glyphicons-halflings-regular.woff
Normal file
Binary file not shown.
BIN
revel/skeleton/public/fonts/glyphicons-halflings-regular.woff2
Normal file
BIN
revel/skeleton/public/fonts/glyphicons-halflings-regular.woff2
Normal file
Binary file not shown.
BIN
revel/skeleton/public/img/favicon.png
Normal file
BIN
revel/skeleton/public/img/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
7
revel/skeleton/public/js/bootstrap-3.3.6.min.js
vendored
Normal file
7
revel/skeleton/public/js/bootstrap-3.3.6.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4
revel/skeleton/public/js/jquery-2.2.4.min.js
vendored
Normal file
4
revel/skeleton/public/js/jquery-2.2.4.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
23
revel/skeleton/tests/apptest.go
Normal file
23
revel/skeleton/tests/apptest.go
Normal 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")
|
||||||
|
}
|
||||||
265
revel/test.go
265
revel/test.go
@@ -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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,7 +11,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"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:
|
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
|
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.
|
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")
|
errorf("No import path given.\nRun 'revel help test' for usage.\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
mode := "dev"
|
mode := DefaultRunMode
|
||||||
if len(args) >= 2 {
|
if len(args) >= 2 {
|
||||||
mode = args[1]
|
mode = args[1]
|
||||||
}
|
}
|
||||||
@@ -61,25 +65,10 @@ func testApp(args []string) {
|
|||||||
revel.Init(mode, args[0], "")
|
revel.Init(mode, args[0], "")
|
||||||
|
|
||||||
// Ensure that the testrunner is loaded in this mode.
|
// Ensure that the testrunner is loaded in this mode.
|
||||||
testRunnerFound := false
|
checkTestRunner()
|
||||||
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
|
|
||||||
|
|
||||||
`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a directory to hold the test result files.
|
// 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 {
|
if err = os.RemoveAll(resultPath); err != nil {
|
||||||
errorf("Failed to remove test result directory %s: %s", resultPath, err)
|
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.
|
// 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 {
|
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()
|
app, reverr := harness.Build()
|
||||||
@@ -108,109 +97,27 @@ You can add it to a run mode configuration with the following line:
|
|||||||
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)
|
||||||
|
|
||||||
// Get a list of tests.
|
// Get a list of tests
|
||||||
// Since this is the first request to the server, retry/sleep a couple times
|
var baseURL = fmt.Sprintf("http://127.0.0.1:%d", revel.HTTPPort)
|
||||||
// in case it hasn't finished starting up yet.
|
testSuites, _ := getTestsList(baseURL)
|
||||||
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)
|
|
||||||
|
|
||||||
// If a specific TestSuite[.Method] is specified, only run that suite/test
|
// If a specific TestSuite[.Method] is specified, only run that suite/test
|
||||||
if len(args) == 3 {
|
if len(args) == 3 {
|
||||||
testSuites = filterTestSuites(testSuites, args[2])
|
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()
|
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.
|
// Run each suite.
|
||||||
var (
|
failedResults, overallSuccess := runTestSuites(baseURL, resultPath, testSuites)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
if overallSuccess {
|
if overallSuccess {
|
||||||
writeResultFile(resultPath, "result.passed", "passed")
|
writeResultFile(resultPath, "result.passed", "passed")
|
||||||
fmt.Println("All Tests Passed.")
|
fmt.Println("All Tests Passed.")
|
||||||
} else {
|
} else {
|
||||||
for _, failedResult := range failedResults {
|
for _, failedResult := range *failedResults {
|
||||||
fmt.Printf("Failures:\n")
|
fmt.Printf("Failures:\n")
|
||||||
for _, result := range failedResult.Results {
|
for _, result := range failedResult.Results {
|
||||||
if !result.Passed {
|
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) {
|
func writeResultFile(resultPath, name, content string) {
|
||||||
if err := ioutil.WriteFile(path.Join(resultPath, name), []byte(content), 0666); err != nil {
|
if err := ioutil.WriteFile(filepath.Join(resultPath, name), []byte(content), 0666); err != nil {
|
||||||
errorf("Failed to write result file %s: %s", path.Join(resultPath, name), err)
|
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
|
// Filters test suites and individual tests to match
|
||||||
// the parsed command line parameter
|
// 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
|
var suiteName, testName string
|
||||||
argArray := strings.Split(suiteArgument, ".")
|
argArray := strings.Split(suiteArgument, ".")
|
||||||
suiteName = argArray[0]
|
suiteName = argArray[0]
|
||||||
@@ -249,20 +156,20 @@ func filterTestSuites(suites []controllers.TestSuiteDesc, suiteArgument string)
|
|||||||
if len(argArray) == 2 {
|
if len(argArray) == 2 {
|
||||||
testName = argArray[1]
|
testName = argArray[1]
|
||||||
}
|
}
|
||||||
for _, suite := range suites {
|
for _, suite := range *suites {
|
||||||
if suite.Name != suiteName {
|
if suite.Name != suiteName {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if testName == "" {
|
if testName == "" {
|
||||||
return []controllers.TestSuiteDesc{suite}
|
return &[]controllers.TestSuiteDesc{suite}
|
||||||
}
|
}
|
||||||
// Only run a particular test in a suite
|
// Only run a particular test in a suite
|
||||||
for _, test := range suite.Tests {
|
for _, test := range suite.Tests {
|
||||||
if test.Name != testName {
|
if test.Name != testName {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return []controllers.TestSuiteDesc{
|
return &[]controllers.TestSuiteDesc{
|
||||||
controllers.TestSuiteDesc{
|
{
|
||||||
Name: suite.Name,
|
Name: suite.Name,
|
||||||
Tests: []controllers.TestDesc{test},
|
Tests: []controllers.TestDesc{test},
|
||||||
},
|
},
|
||||||
@@ -273,3 +180,125 @@ func filterTestSuites(suites []controllers.TestSuiteDesc, suiteArgument string)
|
|||||||
errorf("Couldn't find test suite %s", suiteName)
|
errorf("Couldn't find test suite %s", suiteName)
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go/build"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
@@ -14,7 +18,7 @@ import (
|
|||||||
"github.com/revel/revel"
|
"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 }
|
type LoggedError struct{ error }
|
||||||
|
|
||||||
func panicOnError(err error, msg string) {
|
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
|
// Get the relative path from the source base, and the corresponding path in
|
||||||
// the dest directory.
|
// the dest directory.
|
||||||
relSrcPath := strings.TrimLeft(srcPath[len(srcDir):], string(os.PathSeparator))
|
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.
|
// Skip dot files and dot directories.
|
||||||
if strings.HasPrefix(relSrcPath, ".") {
|
if strings.HasPrefix(relSrcPath, ".") {
|
||||||
@@ -82,7 +86,7 @@ func mustCopyDir(destDir, srcDir string, data map[string]interface{}) error {
|
|||||||
|
|
||||||
// Create a subdirectory if necessary.
|
// Create a subdirectory if necessary.
|
||||||
if info.IsDir() {
|
if info.IsDir() {
|
||||||
err := os.MkdirAll(path.Join(destDir, relSrcPath), 0777)
|
err := os.MkdirAll(filepath.Join(destDir, relSrcPath), 0777)
|
||||||
if !os.IsExist(err) {
|
if !os.IsExist(err) {
|
||||||
panicOnError(err, "Failed to create directory")
|
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 {
|
func mustTarGzDir(destFilename, srcDir string) string {
|
||||||
zipFile, err := os.Create(destFilename)
|
zipFile, err := os.Create(destFilename)
|
||||||
panicOnError(err, "Failed to create archive")
|
panicOnError(err, "Failed to create archive")
|
||||||
defer zipFile.Close()
|
defer func() {
|
||||||
|
_ = zipFile.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
gzipWriter := gzip.NewWriter(zipFile)
|
gzipWriter := gzip.NewWriter(zipFile)
|
||||||
defer gzipWriter.Close()
|
defer func() {
|
||||||
|
_ = gzipWriter.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
tarWriter := tar.NewWriter(gzipWriter)
|
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() {
|
if info.IsDir() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
srcFile, err := os.Open(srcPath)
|
srcFile, err := os.Open(srcPath)
|
||||||
panicOnError(err, "Failed to read source file")
|
panicOnError(err, "Failed to read source file")
|
||||||
defer srcFile.Close()
|
defer func() {
|
||||||
|
_ = srcFile.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
err = tarWriter.WriteHeader(&tar.Header{
|
err = tarWriter.WriteHeader(&tar.Header{
|
||||||
Name: strings.TrimLeft(srcPath[len(srcDir):], string(os.PathSeparator)),
|
Name: strings.TrimLeft(srcPath[len(srcDir):], string(os.PathSeparator)),
|
||||||
@@ -150,7 +162,15 @@ func empty(dirname string) bool {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
errorf("error opening directory: %s", err)
|
errorf("error opening directory: %s", err)
|
||||||
}
|
}
|
||||||
defer dir.Close()
|
defer func() {
|
||||||
|
_ = dir.Close()
|
||||||
|
}()
|
||||||
results, _ := dir.Readdir(1)
|
results, _ := dir.Readdir(1)
|
||||||
return len(results) == 0
|
return len(results) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func importPathFromCurrentDir() string {
|
||||||
|
pwd, _ := os.Getwd()
|
||||||
|
importPath, _ := filepath.Rel(filepath.Join(build.Default.GOPATH, "src"), pwd)
|
||||||
|
return filepath.ToSlash(importPath)
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
// Revel Framework source code and usage is governed by a MIT style
|
// Revel Framework source code and usage is governed by a MIT style
|
||||||
// license that can be found in the LICENSE file.
|
// 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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
Reference in New Issue
Block a user