mirror of
https://github.com/kevin-DL/revel-cmd.git
synced 2026-01-22 15:05:26 +00:00
Enhancements to Revel command
Reformat of code Allow user to use a mix of command line arguments and flags Enhance the import tool to detect missing packages in the modules side Added test cases for all commands
This commit is contained in:
154
revel/build.go
154
revel/build.go
@@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
var cmdBuild = &Command{
|
||||
UsageLine: "build -i [import path] -t [target path] -r [run mode]",
|
||||
UsageLine: "revel build [-r [run mode]] [import path] [target path] ",
|
||||
Short: "build a Revel application (e.g. for deployment)",
|
||||
Long: `
|
||||
Build the Revel web application named by the given import path.
|
||||
@@ -25,7 +25,7 @@ This allows it to be deployed and run on a machine that lacks a Go installation.
|
||||
|
||||
For example:
|
||||
|
||||
revel build -a github.com/revel/examples/chat -t /tmp/chat
|
||||
revel build github.com/revel/examples/chat /tmp/chat
|
||||
|
||||
`,
|
||||
}
|
||||
@@ -38,10 +38,12 @@ func init() {
|
||||
// The update config updates the configuration command so that it can run
|
||||
func updateBuildConfig(c *model.CommandConfig, args []string) bool {
|
||||
c.Index = model.BUILD
|
||||
// If arguments were passed in then there must be two
|
||||
if len(args) < 2 {
|
||||
fmt.Fprintf(os.Stderr, "%s\n%s", cmdBuild.UsageLine, cmdBuild.Long)
|
||||
return false
|
||||
}
|
||||
|
||||
c.Build.ImportPath = args[0]
|
||||
c.Build.TargetPath = args[1]
|
||||
if len(args) > 2 {
|
||||
@@ -51,75 +53,101 @@ func updateBuildConfig(c *model.CommandConfig, args []string) bool {
|
||||
}
|
||||
|
||||
// The main entry point to build application from command line
|
||||
func buildApp(c *model.CommandConfig) {
|
||||
func buildApp(c *model.CommandConfig) (err error) {
|
||||
appImportPath, destPath, mode := c.ImportPath, c.Build.TargetPath, DefaultRunMode
|
||||
if len(c.Build.Mode) > 0 {
|
||||
mode = c.Build.Mode
|
||||
}
|
||||
|
||||
// Convert target to absolute path
|
||||
destPath, _ = filepath.Abs(destPath)
|
||||
c.Build.TargetPath, _ = filepath.Abs(destPath)
|
||||
c.Build.Mode = mode
|
||||
|
||||
revel_paths := model.NewRevelPaths(mode, appImportPath, "", model.DoNothingRevelCallback)
|
||||
|
||||
// First, verify that it is either already empty or looks like a previous
|
||||
// build (to avoid clobbering anything)
|
||||
if utils.Exists(destPath) && !utils.Empty(destPath) && !utils.Exists(filepath.Join(destPath, "run.sh")) {
|
||||
utils.Logger.Errorf("Abort: %s exists and does not look like a build directory.", destPath)
|
||||
revel_paths, err := model.NewRevelPaths(mode, appImportPath, "", model.NewWrappedRevelCallback(nil, c.PackageResolver))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := os.RemoveAll(destPath); err != nil && !os.IsNotExist(err) {
|
||||
utils.Logger.Error("Remove all error", "error", err)
|
||||
return
|
||||
}
|
||||
buildSafetyCheck(destPath)
|
||||
|
||||
if err := os.MkdirAll(destPath, 0777); err != nil {
|
||||
utils.Logger.Error("makedir error", "error", err)
|
||||
return
|
||||
// Ensure the application can be built, this generates the main file
|
||||
app, err := harness.Build(c, revel_paths)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
app, reverr := harness.Build(c, revel_paths)
|
||||
if reverr != nil {
|
||||
utils.Logger.Error("Failed to build application", "error", reverr)
|
||||
return
|
||||
}
|
||||
|
||||
// Copy files
|
||||
// Included are:
|
||||
// - run scripts
|
||||
// - binary
|
||||
// - revel
|
||||
// - app
|
||||
|
||||
packageFolders, err := buildCopyFiles(c, app, revel_paths)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = buildCopyModules(c, revel_paths, packageFolders)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = buildWriteScripts(c, app)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Copy the files to the target
|
||||
func buildCopyFiles(c *model.CommandConfig, app *harness.App, revel_paths *model.RevelContainer) (packageFolders []string, err error) {
|
||||
appImportPath, destPath := c.ImportPath, c.Build.TargetPath
|
||||
|
||||
// Revel and the app are in a directory structure mirroring import path
|
||||
srcPath := filepath.Join(destPath, "src")
|
||||
destBinaryPath := filepath.Join(destPath, filepath.Base(app.BinaryPath))
|
||||
tmpRevelPath := filepath.Join(srcPath, filepath.FromSlash(model.RevelImportPath))
|
||||
utils.MustCopyFile(destBinaryPath, app.BinaryPath)
|
||||
if err = utils.CopyFile(destBinaryPath, app.BinaryPath); err != nil {
|
||||
return
|
||||
}
|
||||
utils.MustChmod(destBinaryPath, 0755)
|
||||
|
||||
// Copy the templates from the revel
|
||||
_ = utils.MustCopyDir(filepath.Join(tmpRevelPath, "conf"), filepath.Join(revel_paths.RevelPath, "conf"), nil)
|
||||
_ = utils.MustCopyDir(filepath.Join(tmpRevelPath, "templates"), filepath.Join(revel_paths.RevelPath, "templates"), nil)
|
||||
if err = utils.CopyDir(filepath.Join(tmpRevelPath, "conf"), filepath.Join(revel_paths.RevelPath, "conf"), nil); err != nil {
|
||||
return
|
||||
}
|
||||
if err = utils.CopyDir(filepath.Join(tmpRevelPath, "templates"), filepath.Join(revel_paths.RevelPath, "templates"), nil); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Get the folders to be packaged
|
||||
packageFolders := strings.Split(revel_paths.Config.StringDefault("package.folders", "conf,public,app/views"), ",")
|
||||
for i,p:=range packageFolders {
|
||||
packageFolders = strings.Split(revel_paths.Config.StringDefault("package.folders", "conf,public,app/views"), ",")
|
||||
for i, p := range packageFolders {
|
||||
// Clean spaces, reformat slash to filesystem
|
||||
packageFolders[i]=filepath.FromSlash(strings.TrimSpace(p))
|
||||
packageFolders[i] = filepath.FromSlash(strings.TrimSpace(p))
|
||||
}
|
||||
|
||||
if c.Build.CopySource {
|
||||
_ = utils.MustCopyDir(filepath.Join(srcPath, filepath.FromSlash(appImportPath)), revel_paths.BasePath, nil)
|
||||
err = utils.CopyDir(filepath.Join(srcPath, filepath.FromSlash(appImportPath)), revel_paths.BasePath, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
for _, folder := range packageFolders {
|
||||
_ = utils.MustCopyDir(
|
||||
err = utils.CopyDir(
|
||||
filepath.Join(srcPath, filepath.FromSlash(appImportPath), folder),
|
||||
filepath.Join(revel_paths.BasePath, folder),
|
||||
nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Based on the section copy over the build modules
|
||||
func buildCopyModules(c *model.CommandConfig, revel_paths *model.RevelContainer, packageFolders []string) (err error) {
|
||||
destPath := filepath.Join(c.Build.TargetPath, "src")
|
||||
// Find all the modules used and copy them over.
|
||||
config := revel_paths.Config.Raw()
|
||||
modulePaths := make(map[string]string) // import path => filesystem path
|
||||
@@ -151,40 +179,76 @@ func buildApp(c *model.CommandConfig) {
|
||||
|
||||
// Copy the the paths for each of the modules
|
||||
for importPath, fsPath := range modulePaths {
|
||||
utils.Logger.Info("Copy files ", "to", filepath.Join(srcPath, importPath), "from", fsPath)
|
||||
utils.Logger.Info("Copy files ", "to", filepath.Join(destPath, importPath), "from", fsPath)
|
||||
if c.Build.CopySource {
|
||||
_ = utils.MustCopyDir(filepath.Join(srcPath, importPath), fsPath, nil)
|
||||
err = utils.CopyDir(filepath.Join(destPath, importPath), fsPath, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
for _, folder := range packageFolders {
|
||||
_ = utils.MustCopyDir(
|
||||
filepath.Join(srcPath, importPath, folder),
|
||||
err = utils.CopyDir(
|
||||
filepath.Join(destPath, importPath, folder),
|
||||
filepath.Join(fsPath, folder),
|
||||
nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Write the run scripts for the build
|
||||
func buildWriteScripts(c *model.CommandConfig, app *harness.App) (err error) {
|
||||
tmplData := map[string]interface{}{
|
||||
"BinName": filepath.Base(app.BinaryPath),
|
||||
"ImportPath": appImportPath,
|
||||
"Mode": mode,
|
||||
"ImportPath": c.Build.ImportPath,
|
||||
"Mode": c.Build.Mode,
|
||||
}
|
||||
|
||||
utils.MustGenerateTemplate(
|
||||
filepath.Join(destPath, "run.sh"),
|
||||
err = utils.GenerateTemplate(
|
||||
filepath.Join(c.Build.TargetPath, "run.sh"),
|
||||
PACKAGE_RUN_SH,
|
||||
tmplData,
|
||||
)
|
||||
utils.MustChmod(filepath.Join(destPath, "run.sh"), 0755)
|
||||
utils.MustGenerateTemplate(
|
||||
filepath.Join(destPath, "run.bat"),
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
utils.MustChmod(filepath.Join(c.Build.TargetPath, "run.sh"), 0755)
|
||||
err = utils.GenerateTemplate(
|
||||
filepath.Join(c.Build.TargetPath, "run.bat"),
|
||||
PACKAGE_RUN_BAT,
|
||||
tmplData,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Your application has been built in:", destPath)
|
||||
fmt.Println("Your application has been built in:", c.Build.TargetPath)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Checks to see if the target folder exists and can be created
|
||||
func buildSafetyCheck(destPath string) error {
|
||||
|
||||
// First, verify that it is either already empty or looks like a previous
|
||||
// build (to avoid clobbering anything)
|
||||
if utils.Exists(destPath) && !utils.Empty(destPath) && !utils.Exists(filepath.Join(destPath, "run.sh")) {
|
||||
return utils.NewBuildError("Abort: %s exists and does not look like a build directory.", "path", destPath)
|
||||
}
|
||||
|
||||
if err := os.RemoveAll(destPath); err != nil && !os.IsNotExist(err) {
|
||||
return utils.NewBuildIfError(err, "Remove all error", "path", destPath)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(destPath, 0777); err != nil {
|
||||
return utils.NewBuildIfError(err, "MkDir all error", "path", destPath)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const PACKAGE_RUN_SH = `#!/bin/sh
|
||||
|
||||
34
revel/build_test.go
Normal file
34
revel/build_test.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"github.com/revel/cmd/model"
|
||||
"github.com/revel/cmd/revel"
|
||||
"github.com/revel/cmd/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// test the commands
|
||||
func TestBuild(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
gopath := setup("revel-test-build", a)
|
||||
|
||||
t.Run("Build", func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
c := newApp("build-test", model.NEW, nil, a)
|
||||
main.Commands[model.NEW].RunWith(c)
|
||||
c.Index = model.BUILD
|
||||
c.Build.TargetPath = filepath.Join(gopath, "build-test", "target")
|
||||
c.Build.ImportPath = c.ImportPath
|
||||
a.Nil(main.Commands[model.BUILD].RunWith(c), "Failed to run build-test")
|
||||
a.True(utils.Exists(filepath.Join(gopath, "build-test", "target")))
|
||||
})
|
||||
|
||||
if !t.Failed() {
|
||||
if err := os.RemoveAll(gopath); err != nil {
|
||||
a.Fail("Failed to remove test path")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,14 +14,14 @@ import (
|
||||
)
|
||||
|
||||
var cmdClean = &Command{
|
||||
UsageLine: "clean -i [import path]",
|
||||
UsageLine: "clean [import path]",
|
||||
Short: "clean a Revel application's temp files",
|
||||
Long: `
|
||||
Clean the Revel web application named by the given import path.
|
||||
|
||||
For example:
|
||||
|
||||
revel clean -a github.com/revel/examples/chat
|
||||
revel clean github.com/revel/examples/chat
|
||||
|
||||
It removes the app/tmp and app/routes directory.
|
||||
|
||||
@@ -46,7 +46,7 @@ func updateCleanConfig(c *model.CommandConfig, args []string) bool {
|
||||
}
|
||||
|
||||
// Clean the source directory of generated files
|
||||
func cleanApp(c *model.CommandConfig) {
|
||||
func cleanApp(c *model.CommandConfig) (err error) {
|
||||
appPkg, err := build.Import(c.ImportPath, "", build.FindOnly)
|
||||
if err != nil {
|
||||
utils.Logger.Fatal("Abort: Failed to find import path:", "error", err)
|
||||
@@ -65,4 +65,5 @@ func cleanApp(c *model.CommandConfig) {
|
||||
return
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
37
revel/clean_test.go
Normal file
37
revel/clean_test.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"github.com/revel/cmd/model"
|
||||
"github.com/revel/cmd/revel"
|
||||
"github.com/revel/cmd/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// test the commands
|
||||
func TestClean(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
gopath := setup("revel-test-clean", a)
|
||||
|
||||
|
||||
t.Run("Clean", func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
c := newApp("clean-test", model.NEW, nil, a)
|
||||
main.Commands[model.NEW].RunWith(c)
|
||||
c.Index = model.TEST
|
||||
main.Commands[model.TEST].RunWith(c)
|
||||
a.True(utils.Exists(filepath.Join(gopath, "src", "clean-test", "app", "tmp", "main.go")),
|
||||
"Missing main from path "+filepath.Join(gopath, "src", "clean-test", "app", "tmp", "main.go"))
|
||||
c.Clean.ImportPath = c.ImportPath
|
||||
a.Nil(main.Commands[model.CLEAN].RunWith(c), "Failed to run clean-test")
|
||||
a.False(utils.Exists(filepath.Join(gopath, "src", "clean-test", "app", "tmp", "main.go")),
|
||||
"Did not remove main from path "+filepath.Join(gopath, "src", "clean-test", "app", "tmp", "main.go"))
|
||||
})
|
||||
if !t.Failed() {
|
||||
if err := os.RemoveAll(gopath); err != nil {
|
||||
a.Fail("Failed to remove test path")
|
||||
}
|
||||
}
|
||||
}
|
||||
74
revel/command_test.go
Normal file
74
revel/command_test.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"github.com/revel/cmd/logger"
|
||||
"github.com/revel/cmd/model"
|
||||
"github.com/revel/cmd/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go/build"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Test that the event handler can be attached and it dispatches the event received
|
||||
func setup(suffix string, a *assert.Assertions) (string) {
|
||||
temp := os.TempDir()
|
||||
wd, _ := os.Getwd()
|
||||
utils.InitLogger(wd, logger.LvlInfo)
|
||||
gopath := filepath.Join(temp, "revel-test",suffix)
|
||||
if utils.Exists(gopath) {
|
||||
utils.Logger.Info("Removing test path", "path", gopath)
|
||||
if err := os.RemoveAll(gopath); err != nil {
|
||||
a.Fail("Failed to remove test path")
|
||||
}
|
||||
}
|
||||
err := os.MkdirAll(gopath, os.ModePerm)
|
||||
a.Nil(err, "Failed to create gopath "+gopath)
|
||||
|
||||
// So this is the issue, on the mac when folders are created in a temp folder they are returned like
|
||||
// /var/folders/nz/vv4_9tw56nv9k3tkvyszvwg80000gn/T/revel-test/revel-test-build
|
||||
// But if you change into that directory and read the current folder it is
|
||||
// /private/var/folders/nz/vv4_9tw56nv9k3tkvyszvwg80000gn/T/revel-test/revel-test-build
|
||||
// So to make this work on darwin this code was added
|
||||
os.Chdir(gopath)
|
||||
newwd, _ := os.Getwd()
|
||||
gopath = newwd
|
||||
defaultBuild := build.Default
|
||||
defaultBuild.GOPATH = gopath
|
||||
build.Default = defaultBuild
|
||||
utils.Logger.Info("Setup stats", "original wd", wd, "new wd", newwd, "gopath",gopath, "gopath exists", utils.DirExists(gopath), "wd exists", utils.DirExists(newwd))
|
||||
|
||||
return gopath
|
||||
}
|
||||
|
||||
// Create a new app for the name
|
||||
func newApp(name string, command model.COMMAND, precall func(c *model.CommandConfig), a *assert.Assertions) *model.CommandConfig {
|
||||
c := &model.CommandConfig{}
|
||||
switch command {
|
||||
case model.NEW:
|
||||
c.New.ImportPath = name
|
||||
case model.BUILD:
|
||||
c.Build.ImportPath = name
|
||||
case model.TEST:
|
||||
c.Test.ImportPath = name
|
||||
case model.PACKAGE:
|
||||
c.Package.ImportPath = name
|
||||
case model.VERSION:
|
||||
c.Version.ImportPath = name
|
||||
case model.CLEAN:
|
||||
c.Clean.ImportPath = name
|
||||
default:
|
||||
a.Fail("Unknown command ", command)
|
||||
}
|
||||
|
||||
c.Index = command
|
||||
if precall != nil {
|
||||
precall(c)
|
||||
}
|
||||
if !c.UpdateImportPath() {
|
||||
a.Fail("Unable to update import path")
|
||||
}
|
||||
c.InitGoPaths()
|
||||
c.InitPackageResolver()
|
||||
return c
|
||||
}
|
||||
289
revel/new.go
289
revel/new.go
@@ -5,7 +5,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"math/rand"
|
||||
@@ -16,6 +15,7 @@ import (
|
||||
|
||||
"github.com/revel/cmd/model"
|
||||
"github.com/revel/cmd/utils"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
var cmdNew = &Command{
|
||||
@@ -51,83 +51,105 @@ func updateNewConfig(c *model.CommandConfig, args []string) bool {
|
||||
return false
|
||||
}
|
||||
c.New.ImportPath = args[0]
|
||||
if len(args)>1 {
|
||||
c.New.Skeleton = args[1]
|
||||
if len(args) > 1 {
|
||||
c.New.SkeletonPath = args[1]
|
||||
}
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
// Call to create a new application
|
||||
func newApp(c *model.CommandConfig) {
|
||||
// check for proper args by count
|
||||
c.SkeletonPath = c.New.Skeleton
|
||||
|
||||
// Check for an existing folder so we dont clober it
|
||||
c.AppPath = filepath.Join(c.SrcRoot, filepath.FromSlash(c.ImportPath))
|
||||
_, err := build.Import(c.ImportPath, "", build.FindOnly)
|
||||
if err==nil || !utils.Empty(c.AppPath) {
|
||||
utils.Logger.Fatal("Abort: Import path already exists.","path", c.ImportPath)
|
||||
func newApp(c *model.CommandConfig) (err error) {
|
||||
// Check for an existing folder so we don't clobber it
|
||||
_, err = build.Import(c.ImportPath, "", build.FindOnly)
|
||||
if err == nil || !utils.Empty(c.AppPath) {
|
||||
return utils.NewBuildError("Abort: Import path already exists.", "path", c.ImportPath)
|
||||
}
|
||||
if err := os.MkdirAll(c.AppPath, os.ModePerm); err != nil {
|
||||
return utils.NewBuildError("Abort: Unable to create app path.", "path", c.AppPath)
|
||||
}
|
||||
|
||||
if c.New.Vendored {
|
||||
depPath, err := exec.LookPath("dep")
|
||||
if err != nil {
|
||||
// Do not halt build unless a new package needs to be imported
|
||||
utils.Logger.Fatal("New: `dep` executable not found in PATH, but vendor folder requested." +
|
||||
"You must install the dep tool before creating a vendored project. " +
|
||||
"You can install the `dep` tool by doing a `go get -u github.com/golang/dep/cmd/dep`")
|
||||
}
|
||||
vendorPath := filepath.Join(c.ImportPath,"vendor")
|
||||
if !utils.DirExists(vendorPath) {
|
||||
err := os.MkdirAll(vendorPath,os.ModePerm)
|
||||
utils.PanicOnError(err, "Failed to create " + vendorPath)
|
||||
}
|
||||
// In order for dep to run there needs to be a source file in the folder
|
||||
tempPath := filepath.Join(c.ImportPath,"tmp")
|
||||
if !utils.DirExists(tempPath) {
|
||||
err := os.MkdirAll(tempPath,os.ModePerm)
|
||||
utils.PanicOnError(err, "Failed to create " + vendorPath)
|
||||
err = utils.MustGenerateTemplate(filepath.Join(tempPath,"main.go"), NEW_MAIN_FILE, nil)
|
||||
utils.PanicOnError(err, "Failed to create main file " + vendorPath)
|
||||
utils.Logger.Info("Creating a new vendor app")
|
||||
|
||||
vendorPath := filepath.Join(c.AppPath, "vendor")
|
||||
if !utils.DirExists(vendorPath) {
|
||||
|
||||
if err := os.MkdirAll(vendorPath, os.ModePerm); err != nil {
|
||||
return utils.NewBuildError("Failed to create "+vendorPath, "error", err)
|
||||
}
|
||||
}
|
||||
packageFile := filepath.Join(c.ImportPath,"Gopkg.toml")
|
||||
|
||||
// In order for dep to run there needs to be a source file in the folder
|
||||
tempPath := filepath.Join(c.AppPath, "tmp")
|
||||
utils.Logger.Info("Checking for temp folder for source code", "path", tempPath)
|
||||
if !utils.DirExists(tempPath) {
|
||||
if err := os.MkdirAll(tempPath, os.ModePerm); err != nil {
|
||||
return utils.NewBuildIfError(err, "Failed to create "+vendorPath)
|
||||
}
|
||||
|
||||
if err = utils.GenerateTemplate(filepath.Join(tempPath, "main.go"), NEW_MAIN_FILE, nil); err != nil {
|
||||
return utils.NewBuildIfError(err, "Failed to create main file "+vendorPath)
|
||||
}
|
||||
}
|
||||
|
||||
// Create a package template file if it does not exist
|
||||
packageFile := filepath.Join(c.AppPath, "Gopkg.toml")
|
||||
utils.Logger.Info("Checking for Gopkg.toml", "path", packageFile)
|
||||
if !utils.Exists(packageFile) {
|
||||
utils.MustGenerateTemplate(packageFile,VENDOR_GOPKG,nil)
|
||||
utils.Logger.Info("Generating Gopkg.toml", "path", packageFile)
|
||||
if err := utils.GenerateTemplate(packageFile, VENDOR_GOPKG, nil); err != nil {
|
||||
return utils.NewBuildIfError(err, "Failed to generate template")
|
||||
}
|
||||
} else {
|
||||
utils.Logger.Info("Package file exists in skeleto, skipping adding")
|
||||
}
|
||||
|
||||
getCmd := exec.Command(depPath, "ensure", "-v")
|
||||
getCmd.Dir = c.ImportPath
|
||||
getCmd := exec.Command("dep", "ensure", "-v")
|
||||
utils.CmdInit(getCmd, c.AppPath)
|
||||
utils.Logger.Info("Exec:", "args", getCmd.Args)
|
||||
getOutput, err := getCmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return utils.NewBuildIfError(err, string(getOutput))
|
||||
}
|
||||
}
|
||||
|
||||
// checking and setting application
|
||||
|
||||
if err = setApplicationPath(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// checking and setting skeleton
|
||||
if err=setSkeletonPath(c);err!=nil {
|
||||
return
|
||||
}
|
||||
|
||||
// copy files to new app directory
|
||||
if err = copyNewAppFiles(c);err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Rerun the dep tool if vendored
|
||||
if c.New.Vendored {
|
||||
getCmd := exec.Command("dep", "ensure", "-v")
|
||||
utils.CmdInit(getCmd, c.AppPath)
|
||||
utils.Logger.Info("Exec:", "args", getCmd.Args)
|
||||
getCmd.Dir = c.ImportPath
|
||||
getOutput, err := getCmd.CombinedOutput()
|
||||
if err != nil {
|
||||
utils.Logger.Fatal(string(getOutput))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// checking and setting application
|
||||
setApplicationPath(c)
|
||||
|
||||
// checking and setting skeleton
|
||||
setSkeletonPath(c)
|
||||
|
||||
// copy files to new app directory
|
||||
copyNewAppFiles(c)
|
||||
|
||||
|
||||
// goodbye world
|
||||
fmt.Fprintln(os.Stdout, "Your application is ready:\n ", c.AppPath)
|
||||
fmt.Fprintln(os.Stdout, "Your application has been created in:\n ", c.AppPath)
|
||||
// Check to see if it should be run right off
|
||||
if c.New.Run {
|
||||
runApp(c)
|
||||
} else {
|
||||
fmt.Fprintln(os.Stdout, "\nYou can run it with:\n revel run -a ", c.ImportPath)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Used to generate a new secret key
|
||||
@@ -143,7 +165,7 @@ func generateSecret() string {
|
||||
}
|
||||
|
||||
// Sets the applicaiton path
|
||||
func setApplicationPath(c *model.CommandConfig) {
|
||||
func setApplicationPath(c *model.CommandConfig) (err error) {
|
||||
|
||||
// revel/revel#1014 validate relative path, we cannot use built-in functions
|
||||
// since Go import path is valid relative path too.
|
||||
@@ -153,95 +175,134 @@ func setApplicationPath(c *model.CommandConfig) {
|
||||
c.ImportPath)
|
||||
}
|
||||
|
||||
|
||||
// If we are running a vendored version of Revel we do not need to check for it.
|
||||
if !c.New.Vendored {
|
||||
var err error
|
||||
_, err = build.Import(model.RevelImportPath, "", build.FindOnly)
|
||||
if err != nil {
|
||||
// Go get the revel project
|
||||
getCmd := exec.Command(c.GoCmd, "get", model.RevelImportPath)
|
||||
utils.Logger.Info("Exec:" + c.GoCmd, "args", getCmd.Args)
|
||||
getOutput, err := getCmd.CombinedOutput()
|
||||
//// Go get the revel project
|
||||
err = c.PackageResolver(model.RevelImportPath)
|
||||
if err != nil {
|
||||
utils.Logger.Fatal("Failed to fetch revel " + model.RevelImportPath, "getOutput", string(getOutput))
|
||||
return utils.NewBuildIfError(err, "Failed to fetch revel "+model.RevelImportPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.AppName = filepath.Base(c.AppPath)
|
||||
c.BasePath = filepath.ToSlash(filepath.Dir(c.ImportPath))
|
||||
|
||||
if c.BasePath == "." {
|
||||
// we need to remove the a single '.' when
|
||||
// the app is in the $GOROOT/src directory
|
||||
c.BasePath = ""
|
||||
} else {
|
||||
// we need to append a '/' when the app is
|
||||
// is a subdirectory such as $GOROOT/src/path/to/revelapp
|
||||
c.BasePath += "/"
|
||||
}
|
||||
//if c.BasePath == "." {
|
||||
// // we need to remove the a single '.' when
|
||||
// // the app is in the $GOROOT/src directory
|
||||
// c.BasePath = ""
|
||||
//} else {
|
||||
// // we need to append a '/' when the app is
|
||||
// // is a subdirectory such as $GOROOT/src/path/to/revelapp
|
||||
// c.BasePath += "/"
|
||||
//}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set the skeleton path
|
||||
func setSkeletonPath(c *model.CommandConfig) {
|
||||
var err error
|
||||
if len(c.SkeletonPath) > 0 { // user specified
|
||||
|
||||
_, err = build.Import(c.SkeletonPath, "", build.FindOnly)
|
||||
if err != nil {
|
||||
// Execute "go get <pkg>"
|
||||
getCmd := exec.Command(c.GoCmd, "get", "-d", c.SkeletonPath)
|
||||
fmt.Println("Exec:", getCmd.Args)
|
||||
getOutput, err := getCmd.CombinedOutput()
|
||||
|
||||
// check getOutput for no buildible string
|
||||
bpos := bytes.Index(getOutput, []byte("no buildable Go source files in"))
|
||||
if err != nil && bpos == -1 {
|
||||
utils.Logger.Fatalf("Abort: Could not find or 'go get' Skeleton source code: %s\n%s\n", getOutput, c.SkeletonPath)
|
||||
}
|
||||
}
|
||||
// use the
|
||||
c.SkeletonPath = filepath.Join(c.SrcRoot, c.SkeletonPath)
|
||||
|
||||
} else {
|
||||
// use the revel default
|
||||
revelCmdPkg, err := build.Import(RevelCmdImportPath, "", build.FindOnly)
|
||||
if err != nil {
|
||||
if err != nil {
|
||||
// Go get the revel project
|
||||
getCmd := exec.Command(c.GoCmd, "get", RevelCmdImportPath + "/revel")
|
||||
utils.Logger.Info("Exec:" + c.GoCmd, "args", getCmd.Args)
|
||||
getOutput, err := getCmd.CombinedOutput()
|
||||
if err != nil {
|
||||
utils.Logger.Fatal("Failed to fetch revel cmd " + RevelCmdImportPath, "getOutput", string(getOutput))
|
||||
}
|
||||
revelCmdPkg, err = build.Import(RevelCmdImportPath, "", build.FindOnly)
|
||||
if err!= nil {
|
||||
utils.Logger.Fatal("Failed to find source of revel cmd " + RevelCmdImportPath, "getOutput", string(getOutput), "error",err, "dir", revelCmdPkg.Dir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.SkeletonPath = filepath.Join(revelCmdPkg.Dir, "revel", "skeleton")
|
||||
func setSkeletonPath(c *model.CommandConfig) (err error) {
|
||||
if len(c.New.SkeletonPath) == 0 {
|
||||
c.New.SkeletonPath = RevelCmdImportPath + ":skeleton"
|
||||
}
|
||||
|
||||
// First check to see the protocol of the string
|
||||
if sp, err := url.Parse(c.New.SkeletonPath); err == nil {
|
||||
utils.Logger.Info("Detected skeleton path", "path", sp)
|
||||
|
||||
switch strings.ToLower(sp.Scheme) {
|
||||
// TODO Add support for https, http, ftp, file
|
||||
case "git":
|
||||
if err := newLoadFromGit(c, sp); err != nil {
|
||||
return err
|
||||
}
|
||||
case "":
|
||||
if err := newLoadFromGo(c, sp); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
utils.Logger.Fatal("Unsupported")
|
||||
|
||||
}
|
||||
// TODO check to see if the path needs to be extracted
|
||||
} else {
|
||||
utils.Logger.Fatal("Invalid skeleton path format", "path", c.New.SkeletonPath)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func copyNewAppFiles(c *model.CommandConfig) {
|
||||
var err error
|
||||
err = os.MkdirAll(c.AppPath, 0777)
|
||||
utils.PanicOnError(err, "Failed to create directory "+c.AppPath)
|
||||
// Load skeleton from git
|
||||
func newLoadFromGit(c *model.CommandConfig, sp *url.URL) (err error) {
|
||||
// This method indicates we need to fetch from a repository using git
|
||||
// Execute "git clone get <pkg>"
|
||||
targetPath := filepath.Join(os.TempDir(), "revel", "skeleton")
|
||||
os.RemoveAll(targetPath)
|
||||
pathpart := strings.Split(sp.Path, ":")
|
||||
getCmd := exec.Command("git", "clone", sp.Scheme+"://"+sp.Host+pathpart[0], targetPath)
|
||||
utils.Logger.Info("Exec:", "args", getCmd.Args)
|
||||
getOutput, err := getCmd.CombinedOutput()
|
||||
if err != nil {
|
||||
utils.Logger.Fatalf("Abort: could not clone the Skeleton source code: \n%s\n%s\n", getOutput, c.New.SkeletonPath)
|
||||
}
|
||||
outputPath := targetPath
|
||||
if len(pathpart) > 1 {
|
||||
outputPath = filepath.Join(targetPath, filepath.Join(strings.Split(pathpart[1], string('/'))...))
|
||||
}
|
||||
outputPath, _ = filepath.Abs(outputPath)
|
||||
if !strings.HasPrefix(outputPath, targetPath) {
|
||||
utils.Logger.Fatal("Unusual target path outside root path", "target", outputPath, "root", targetPath)
|
||||
}
|
||||
|
||||
_ = utils.MustCopyDir(c.AppPath, c.SkeletonPath, map[string]interface{}{
|
||||
c.New.SkeletonPath = outputPath
|
||||
return
|
||||
}
|
||||
|
||||
// Load from GO
|
||||
func newLoadFromGo(c *model.CommandConfig, sp *url.URL) (err error) {
|
||||
// Find the source paths, download packages automatically
|
||||
pathpart := strings.Split(sp.Path, ":")
|
||||
_, skeletonImportPath , err := utils.FindSrcPaths(c.ImportPath,sp.Host+pathpart[0],c.PackageResolver)
|
||||
if err!=nil {
|
||||
return
|
||||
}
|
||||
|
||||
skeletonImportPath = filepath.Join(skeletonImportPath,sp.Host,pathpart[0])
|
||||
// Add in anything after the "Root" path
|
||||
if len(pathpart) > 1 {
|
||||
pathpart[0] = skeletonImportPath
|
||||
newdir, _ := filepath.Abs(filepath.Join(pathpart...))
|
||||
if !strings.HasPrefix(newdir, skeletonImportPath) {
|
||||
utils.Logger.Fatal("Unusual target path outside root path", "target", newdir, "root", skeletonImportPath)
|
||||
}
|
||||
skeletonImportPath = newdir
|
||||
}
|
||||
|
||||
c.New.SkeletonPath = skeletonImportPath
|
||||
return
|
||||
}
|
||||
|
||||
func copyNewAppFiles(c *model.CommandConfig) (err error) {
|
||||
err = os.MkdirAll(c.AppPath, 0777)
|
||||
if err != nil {
|
||||
return utils.NewBuildIfError(err, "MKDIR failed")
|
||||
}
|
||||
|
||||
err = utils.CopyDir(c.AppPath, c.New.SkeletonPath, map[string]interface{}{
|
||||
// app.conf
|
||||
"AppName": c.AppName,
|
||||
"BasePath": c.BasePath,
|
||||
"BasePath": c.AppPath,
|
||||
"Secret": generateSecret(),
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Printf("err %v", err)
|
||||
return utils.NewBuildIfError(err, "Copy Dir failed")
|
||||
}
|
||||
|
||||
// Dotfiles are skipped by mustCopyDir, so we have to explicitly copy the .gitignore.
|
||||
gitignore := ".gitignore"
|
||||
utils.MustCopyFile(filepath.Join(c.AppPath, gitignore), filepath.Join(c.SkeletonPath, gitignore))
|
||||
return utils.CopyFile(filepath.Join(c.AppPath, gitignore), filepath.Join(c.New.SkeletonPath, gitignore))
|
||||
|
||||
}
|
||||
|
||||
@@ -299,4 +360,4 @@ required = ["github.com/revel/cmd/revel"]
|
||||
NEW_MAIN_FILE = `package main
|
||||
|
||||
`
|
||||
)
|
||||
)
|
||||
|
||||
107
revel/new_test.go
Normal file
107
revel/new_test.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"github.com/revel/cmd/model"
|
||||
"github.com/revel/cmd/revel"
|
||||
"github.com/revel/cmd/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// test the commands
|
||||
func TestNew(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
gopath := setup("revel-test-new", a)
|
||||
|
||||
t.Run("New", func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
c := newApp("new-test", model.NEW, nil, a)
|
||||
a.Nil(main.Commands[model.NEW].RunWith(c), "New failed")
|
||||
})
|
||||
t.Run("Path", func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
c := newApp("new/test/a", model.NEW, nil, a)
|
||||
a.Nil(main.Commands[model.NEW].RunWith(c), "New path failed")
|
||||
})
|
||||
t.Run("Path-Duplicate", func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
c := newApp("new/test/b", model.NEW, nil, a)
|
||||
a.Nil(main.Commands[model.NEW].RunWith(c), "New path failed")
|
||||
c = newApp("new/test/b", model.NEW, nil, a)
|
||||
a.NotNil(main.Commands[model.NEW].RunWith(c), "Duplicate path Did Not failed")
|
||||
})
|
||||
t.Run("Skeleton-Git", func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
c := newApp("new/test/c/1", model.NEW, nil, a)
|
||||
c.New.SkeletonPath = "git://github.com/revel/cmd:skeleton2"
|
||||
a.NotNil(main.Commands[model.NEW].RunWith(c), "Expected Failed to run with new")
|
||||
// We need to pick a different path
|
||||
c = newApp("new/test/c/2", model.NEW, nil, a)
|
||||
c.New.SkeletonPath = "git://github.com/revel/cmd:skeleton"
|
||||
a.Nil(main.Commands[model.NEW].RunWith(c), "Failed to run with new skeleton git")
|
||||
})
|
||||
t.Run("Skeleton-Go", func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
c := newApp("new/test/d", model.NEW, nil, a)
|
||||
c.New.SkeletonPath = "github.com/revel/cmd:skeleton"
|
||||
a.Nil(main.Commands[model.NEW].RunWith(c), "Failed to run with new from go")
|
||||
})
|
||||
if !t.Failed() {
|
||||
if err := os.RemoveAll(gopath); err != nil {
|
||||
a.Fail("Failed to remove test path")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test the commands
|
||||
func TestNewVendor(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
gopath := setup("revel-test-new-vendor", a)
|
||||
precall := func(c *model.CommandConfig) {
|
||||
c.New.Vendored = true
|
||||
}
|
||||
t.Run("New", func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
c := newApp("onlyone/v/a", model.NEW, precall, a)
|
||||
c.New.Vendored = true
|
||||
a.Nil(main.Commands[model.NEW].RunWith(c), "New failed")
|
||||
})
|
||||
t.Run("Test", func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
c := newApp("onlyone/v/a", model.TEST, nil, a)
|
||||
a.Nil(main.Commands[model.TEST].RunWith(c), "Test failed")
|
||||
})
|
||||
t.Run("Build", func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
c := newApp("onlyone/v/a", model.BUILD, nil, a)
|
||||
c.Index = model.BUILD
|
||||
c.Build.TargetPath = filepath.Join(gopath, "src/onlyone/v/a", "target")
|
||||
a.Nil(main.Commands[model.BUILD].RunWith(c), " Build failed")
|
||||
a.True(utils.DirExists(c.Build.TargetPath), "Target folder not made", c.Build.TargetPath)
|
||||
})
|
||||
t.Run("Package", func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
c := newApp("onlyone/v/a", model.PACKAGE, nil, a)
|
||||
c.Package.TargetPath = filepath.Join(gopath, "src/onlyone/v/a", "target.tar.gz")
|
||||
a.Nil(main.Commands[model.PACKAGE].RunWith(c), "Package Failed")
|
||||
a.True(utils.Exists(c.Package.TargetPath), "Target package not made", c.Package.TargetPath)
|
||||
})
|
||||
t.Run("TestVendorDir", func(t *testing.T) {
|
||||
// Check to see that no additional packages were downloaded outside the vendor folder
|
||||
files, err := ioutil.ReadDir(gopath)
|
||||
a.Nil(err, "Failed to read gopath folder")
|
||||
// bin/ onlyone/ pkg/ src/
|
||||
a.Equal(3, len(files), "Expected single file in "+gopath)
|
||||
files, err = ioutil.ReadDir(filepath.Join(gopath, "src"))
|
||||
a.Nil(err, "Failed to read src folder")
|
||||
a.Equal(1, len(files), "Expected single file in source folder", filepath.Join(gopath, "src"))
|
||||
})
|
||||
if !t.Failed() {
|
||||
if err := os.RemoveAll(gopath); err != nil {
|
||||
a.Fail("Failed to remove test path")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
var cmdPackage = &Command{
|
||||
UsageLine: "package -i [import path] -r [run mode]",
|
||||
UsageLine: "package [-r [run mode]] [application] ",
|
||||
Short: "package a Revel application (e.g. for deployment)",
|
||||
Long: `
|
||||
Package the Revel web application named by the given import path.
|
||||
@@ -28,7 +28,7 @@ Run mode defaults to "dev".
|
||||
|
||||
For example:
|
||||
|
||||
revel package -i github.com/revel/examples/chat
|
||||
revel package github.com/revel/examples/chat
|
||||
`,
|
||||
}
|
||||
|
||||
@@ -40,19 +40,16 @@ func init() {
|
||||
// Called when unable to parse the command line automatically and assumes an old launch
|
||||
func updatePackageConfig(c *model.CommandConfig, args []string) bool {
|
||||
c.Index = model.PACKAGE
|
||||
if len(args) == 0 {
|
||||
fmt.Fprintf(os.Stderr, cmdPackage.Long)
|
||||
return false
|
||||
}
|
||||
c.Package.ImportPath = args[0]
|
||||
if len(args)>1 {
|
||||
if len(args) > 1 {
|
||||
c.Package.Mode = args[1]
|
||||
}
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
func packageApp(c *model.CommandConfig) {
|
||||
// Called to package the app
|
||||
func packageApp(c *model.CommandConfig) (err error) {
|
||||
|
||||
// Determine the run mode.
|
||||
mode := DefaultRunMode
|
||||
@@ -61,13 +58,22 @@ func packageApp(c *model.CommandConfig) {
|
||||
}
|
||||
|
||||
appImportPath := c.ImportPath
|
||||
revel_paths := model.NewRevelPaths(mode, appImportPath, "", model.DoNothingRevelCallback)
|
||||
revel_paths, err := model.NewRevelPaths(mode, appImportPath, "", model.NewWrappedRevelCallback(nil, c.PackageResolver))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Remove the archive if it already exists.
|
||||
destFile := filepath.Base(revel_paths.BasePath) + ".tar.gz"
|
||||
destFile := filepath.Join(c.AppPath, filepath.Base(revel_paths.BasePath)+".tar.gz")
|
||||
if c.Package.TargetPath != "" {
|
||||
if filepath.IsAbs(c.Package.TargetPath) {
|
||||
destFile = c.Package.TargetPath
|
||||
} else {
|
||||
destFile = filepath.Join(c.AppPath, c.Package.TargetPath)
|
||||
}
|
||||
}
|
||||
if err := os.Remove(destFile); err != nil && !os.IsNotExist(err) {
|
||||
utils.Logger.Error("Unable to remove target file","error",err,"file",destFile)
|
||||
os.Exit(1)
|
||||
return utils.NewBuildError("Unable to remove target file", "error", err, "file", destFile)
|
||||
}
|
||||
|
||||
// Collect stuff in a temp directory.
|
||||
@@ -83,7 +89,12 @@ func packageApp(c *model.CommandConfig) {
|
||||
buildApp(c)
|
||||
|
||||
// Create the zip file.
|
||||
archiveName := utils.MustTarGzDir(destFile, tmpDir)
|
||||
|
||||
archiveName, err := utils.TarGzDir(destFile, tmpDir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Your archive is ready:", archiveName)
|
||||
return
|
||||
}
|
||||
|
||||
30
revel/package_test.go
Normal file
30
revel/package_test.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"github.com/revel/cmd/model"
|
||||
"github.com/revel/cmd/revel"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// test the commands
|
||||
func TestPackage(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
gopath := setup("revel-test-package", a)
|
||||
|
||||
t.Run("Package", func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
c := newApp("package-test", model.NEW, nil, a)
|
||||
main.Commands[model.NEW].RunWith(c)
|
||||
c.Index = model.PACKAGE
|
||||
c.Package.ImportPath = c.ImportPath
|
||||
a.Nil(main.Commands[model.PACKAGE].RunWith(c), "Failed to run package-test")
|
||||
})
|
||||
|
||||
if !t.Failed() {
|
||||
if err := os.RemoveAll(gopath); err != nil {
|
||||
a.Fail("Failed to remove test path")
|
||||
}
|
||||
}
|
||||
}
|
||||
265
revel/revel.go
265
revel/revel.go
@@ -8,23 +8,18 @@ package main
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/jessevdk/go-flags"
|
||||
|
||||
"github.com/agtorre/gocolorize"
|
||||
"github.com/revel/cmd/logger"
|
||||
"github.com/revel/cmd/model"
|
||||
"github.com/revel/cmd/utils"
|
||||
"github.com/revel/cmd/logger"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"go/build"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -37,8 +32,8 @@ const (
|
||||
|
||||
// Command structure cribbed from the genius organization of the "go" command.
|
||||
type Command struct {
|
||||
UpdateConfig func(c *model.CommandConfig, args []string) bool
|
||||
RunWith func(c *model.CommandConfig)
|
||||
UpdateConfig func(c *model.CommandConfig, args []string) bool
|
||||
RunWith func(c *model.CommandConfig) error
|
||||
UsageLine, Short, Long string
|
||||
}
|
||||
|
||||
@@ -53,7 +48,7 @@ func (cmd *Command) Name() string {
|
||||
}
|
||||
|
||||
// The commands
|
||||
var commands = []*Command{
|
||||
var Commands = []*Command{
|
||||
nil, // Safety net, prevent missing index from running
|
||||
cmdNew,
|
||||
cmdRun,
|
||||
@@ -63,43 +58,61 @@ var commands = []*Command{
|
||||
cmdTest,
|
||||
cmdVersion,
|
||||
}
|
||||
|
||||
func main() {
|
||||
if runtime.GOOS == "windows" {
|
||||
gocolorize.SetPlain(true)
|
||||
}
|
||||
c := &model.CommandConfig{}
|
||||
wd,_ := os.Getwd()
|
||||
wd, _ := os.Getwd()
|
||||
|
||||
utils.InitLogger(wd,logger.LvlError)
|
||||
utils.InitLogger(wd, logger.LvlError)
|
||||
|
||||
parser := flags.NewParser(c, flags.HelpFlag | flags.PassDoubleDash)
|
||||
if ini:=flag.String("ini","none","");*ini!="none" {
|
||||
if err:=flags.NewIniParser(parser).ParseFile(*ini);err!=nil {
|
||||
utils.Logger.Error("Unable to load ini", "error",err)
|
||||
parser := flags.NewParser(c, flags.HelpFlag|flags.PassDoubleDash)
|
||||
if err := ParseArgs(c, parser, os.Args[1:]); err != nil {
|
||||
fmt.Fprint(os.Stderr, err.Error())
|
||||
parser.WriteHelp(os.Stdout)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Switch based on the verbose flag
|
||||
if len(c.Verbose)>1 {
|
||||
utils.InitLogger(wd, logger.LvlDebug)
|
||||
} else if len(c.Verbose)>0 {
|
||||
utils.InitLogger(wd, logger.LvlInfo)
|
||||
} else {
|
||||
utils.InitLogger(wd, logger.LvlWarn)
|
||||
}
|
||||
|
||||
if !c.UpdateImportPath() {
|
||||
utils.Logger.Fatal("Unable to determine application path")
|
||||
}
|
||||
|
||||
command := Commands[c.Index]
|
||||
println("Revel executing:", command.Short)
|
||||
|
||||
// Setting go paths
|
||||
c.InitGoPaths()
|
||||
|
||||
// Setup package resolver
|
||||
c.InitPackageResolver()
|
||||
|
||||
if err := command.RunWith(c); err != nil {
|
||||
utils.Logger.Error("Unable to execute","error",err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the arguments passed into the model.CommandConfig
|
||||
func ParseArgs(c *model.CommandConfig, parser *flags.Parser, args []string) (err error) {
|
||||
var extraArgs []string
|
||||
if ini := flag.String("ini", "none", ""); *ini != "none" {
|
||||
if err = flags.NewIniParser(parser).ParseFile(*ini); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if _, err := parser.Parse(); err != nil {
|
||||
utils.Logger.Info("Command line options failed", "error", err.Error())
|
||||
|
||||
// Decode nature of error
|
||||
if perr,ok:=err.(*flags.Error); ok {
|
||||
if perr.Type == flags.ErrRequired {
|
||||
// Try the old way
|
||||
if !main_parse_old(c) {
|
||||
println("Command line error:", err.Error())
|
||||
parser.WriteHelp(os.Stdout)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
println("Command line error:", err.Error())
|
||||
parser.WriteHelp(os.Stdout)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
println("Command line error:", err.Error())
|
||||
parser.WriteHelp(os.Stdout)
|
||||
os.Exit(1)
|
||||
}
|
||||
if extraArgs, err = parser.ParseArgs(args); err != nil {
|
||||
return
|
||||
} else {
|
||||
switch parser.Active.Name {
|
||||
case "new":
|
||||
@@ -120,182 +133,18 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
// Switch based on the verbose flag
|
||||
if c.Verbose {
|
||||
utils.InitLogger(wd, logger.LvlDebug)
|
||||
} else {
|
||||
utils.InitLogger(wd, logger.LvlWarn)
|
||||
}
|
||||
|
||||
if c.Index==0 {
|
||||
utils.Logger.Fatal("Unknown command line arguements")
|
||||
}
|
||||
if !c.UpdateImportPath() {
|
||||
utils.Logger.Fatal("Unable to determine application path")
|
||||
}
|
||||
println("Revel executing:", commands[c.Index].Short)
|
||||
// checking and setting go paths
|
||||
initGoPaths(c)
|
||||
|
||||
|
||||
commands[c.Index].RunWith(c)
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Try to populate the CommandConfig using the old techniques
|
||||
func main_parse_old(c *model.CommandConfig) bool {
|
||||
// Take the old command format and try to parse them
|
||||
flag.Usage = func() { usage(1) }
|
||||
flag.Parse()
|
||||
args := flag.Args()
|
||||
|
||||
if len(args) < 1 || args[0] == "help" {
|
||||
if len(args) == 1 {
|
||||
usage(0)
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
for _, cmd := range commands {
|
||||
if cmd!=nil && cmd.Name() == args[1] {
|
||||
tmpl(os.Stdout, helpTemplate, cmd)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
usage(2)
|
||||
}
|
||||
|
||||
for _, cmd := range commands {
|
||||
if cmd!=nil && cmd.Name() == args[0] {
|
||||
println("Running", cmd.Name())
|
||||
return cmd.UpdateConfig(c, args[1:])
|
||||
if c.Index == 0 {
|
||||
err = fmt.Errorf("Unknown command %v", extraArgs)
|
||||
} else if len(extraArgs) > 0 {
|
||||
utils.Logger.Info("Found additional arguements, setting them")
|
||||
if !Commands[c.Index].UpdateConfig(c, extraArgs) {
|
||||
err = fmt.Errorf("Invalid command line arguements %v", extraArgs)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func main_old() {
|
||||
if runtime.GOOS == "windows" {
|
||||
gocolorize.SetPlain(true)
|
||||
}
|
||||
fmt.Fprintf(os.Stdout, gocolorize.NewColor("blue").Paint(header))
|
||||
flag.Usage = func() { usage(1) }
|
||||
flag.Parse()
|
||||
args := flag.Args()
|
||||
|
||||
if len(args) < 1 || args[0] == "help" {
|
||||
if len(args) == 1 {
|
||||
usage(0)
|
||||
}
|
||||
if len(args) > 1 {
|
||||
for _, cmd := range commands {
|
||||
if cmd.Name() == args[1] {
|
||||
tmpl(os.Stdout, helpTemplate, cmd)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
usage(2)
|
||||
}
|
||||
|
||||
// Commands use panic to abort execution when something goes wrong.
|
||||
// Panics are logged at the point of error. Ignore those.
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
if _, ok := err.(utils.LoggedError); !ok {
|
||||
// This panic was not expected / logged.
|
||||
panic(err)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
|
||||
//for _, cmd := range commands {
|
||||
// if cmd.Name() == args[0] {
|
||||
// cmd.UpdateConfig(args[1:])
|
||||
// return
|
||||
// }
|
||||
//}
|
||||
|
||||
utils.Logger.Fatalf("unknown command %q\nRun 'revel help' for usage.\n", args[0])
|
||||
}
|
||||
|
||||
const header = `~
|
||||
~ revel! http://revel.github.io
|
||||
~
|
||||
`
|
||||
|
||||
const usageTemplate = `usage: revel command [arguments]
|
||||
|
||||
The commands are:
|
||||
{{range .}}
|
||||
{{.Name | printf "%-11s"}} {{.Short}}{{end}}
|
||||
|
||||
Use "revel help [command]" for more information.
|
||||
`
|
||||
|
||||
var helpTemplate = `usage: revel {{.UsageLine}}
|
||||
{{.Long}}
|
||||
`
|
||||
|
||||
func usage(exitCode int) {
|
||||
tmpl(os.Stderr, usageTemplate, commands)
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
|
||||
func tmpl(w io.Writer, text string, data interface{}) {
|
||||
t := template.New("top")
|
||||
template.Must(t.Parse(text))
|
||||
if err := t.Execute(w, data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
// lookup and set Go related variables
|
||||
func initGoPaths(c *model.CommandConfig) {
|
||||
// lookup go path
|
||||
c.GoPath = build.Default.GOPATH
|
||||
if c.GoPath == "" {
|
||||
utils.Logger.Fatal("Abort: GOPATH environment variable is not set. " +
|
||||
"Please refer to http://golang.org/doc/code.html to configure your Go environment.")
|
||||
}
|
||||
|
||||
// check for go executable
|
||||
var err error
|
||||
c.GoCmd, err = exec.LookPath("go")
|
||||
if err != nil {
|
||||
utils.Logger.Fatal("Go executable not found in PATH.")
|
||||
}
|
||||
|
||||
// revel/revel#1004 choose go path relative to current working directory
|
||||
workingDir, _ := os.Getwd()
|
||||
goPathList := filepath.SplitList(c.GoPath)
|
||||
for _, path := range goPathList {
|
||||
if strings.HasPrefix(strings.ToLower(workingDir), strings.ToLower(path)) {
|
||||
c.SrcRoot = path
|
||||
break
|
||||
}
|
||||
|
||||
path, _ = filepath.EvalSymlinks(path)
|
||||
if len(path) > 0 && strings.HasPrefix(strings.ToLower(workingDir), strings.ToLower(path)) {
|
||||
c.SrcRoot = path
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.SrcRoot) == 0 {
|
||||
if c.Index != model.VERSION {
|
||||
utils.Logger.Fatal("Abort: could not create a Revel application outside of GOPATH.")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// set go src path
|
||||
c.SrcRoot = filepath.Join(c.SrcRoot, "src")
|
||||
}
|
||||
46
revel/run.go
46
revel/run.go
@@ -15,23 +15,23 @@ import (
|
||||
)
|
||||
|
||||
var cmdRun = &Command{
|
||||
UsageLine: "run [import path] [run mode] [port]",
|
||||
UsageLine: "run [-m [run mode] -p [port]] [import path] ",
|
||||
Short: "run a Revel application",
|
||||
Long: `
|
||||
Run the Revel web application named by the given import path.
|
||||
|
||||
For example, to run the chat room sample application:
|
||||
|
||||
revel run github.com/revel/examples/chat dev
|
||||
revel run -m dev github.com/revel/examples/chat
|
||||
|
||||
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.
|
||||
|
||||
Run mode defaults to "dev".
|
||||
|
||||
You can set a port as an optional third parameter. For example:
|
||||
You can set a port as well. For example:
|
||||
|
||||
revel run github.com/revel/examples/chat prod 8080`,
|
||||
revel run -m prod -p 8080 github.com/revel/examples/chat `,
|
||||
}
|
||||
|
||||
// RunArgs holds revel run parameters
|
||||
@@ -47,14 +47,23 @@ func init() {
|
||||
}
|
||||
|
||||
func updateRunConfig(c *model.CommandConfig, args []string) bool {
|
||||
|
||||
convertPort := func(value string) int {
|
||||
if value != "" {
|
||||
port, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
utils.Logger.Fatalf("Failed to parse port as integer: %s", c.Run.Port)
|
||||
}
|
||||
return port
|
||||
}
|
||||
return 0
|
||||
}
|
||||
switch len(args) {
|
||||
case 3:
|
||||
// Possible combinations
|
||||
// revel run [import-path] [run-mode] [port]
|
||||
c.Run.ImportPath = args[0]
|
||||
c.Run.Mode = args[1]
|
||||
c.Run.Port = args[2]
|
||||
c.Run.Port = convertPort(args[2])
|
||||
case 2:
|
||||
// Possible combinations
|
||||
// 1. revel run [import-path] [run-mode]
|
||||
@@ -68,7 +77,7 @@ func updateRunConfig(c *model.CommandConfig, args []string) bool {
|
||||
|
||||
if _, err := strconv.Atoi(args[1]); err == nil {
|
||||
// 2nd arg is the port number
|
||||
c.Run.Port = args[1]
|
||||
c.Run.Port = convertPort(args[1])
|
||||
} else {
|
||||
// 2nd arg is the run mode
|
||||
c.Run.Mode = args[1]
|
||||
@@ -76,7 +85,7 @@ func updateRunConfig(c *model.CommandConfig, args []string) bool {
|
||||
} else {
|
||||
// 1st arg is the run mode
|
||||
c.Run.Mode = args[0]
|
||||
c.Run.Port = args[1]
|
||||
c.Run.Port = convertPort(args[1])
|
||||
}
|
||||
case 1:
|
||||
// Possible combinations
|
||||
@@ -93,7 +102,7 @@ func updateRunConfig(c *model.CommandConfig, args []string) bool {
|
||||
c.Run.ImportPath = args[0]
|
||||
} else if _, err := strconv.Atoi(args[0]); err == nil {
|
||||
// 1st arg is the port number
|
||||
c.Run.Port = args[0]
|
||||
c.Run.Port = convertPort(args[0])
|
||||
} else {
|
||||
// 1st arg is the run mode
|
||||
c.Run.Mode = args[0]
|
||||
@@ -105,18 +114,20 @@ func updateRunConfig(c *model.CommandConfig, args []string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func runApp(c *model.CommandConfig) {
|
||||
// Called to run the app
|
||||
func runApp(c *model.CommandConfig) (err error) {
|
||||
if c.Run.Mode == "" {
|
||||
c.Run.Mode = "dev"
|
||||
}
|
||||
|
||||
revel_path := model.NewRevelPaths(c.Run.Mode, c.ImportPath, "", model.DoNothingRevelCallback)
|
||||
if c.Run.Port != "" {
|
||||
port, err := strconv.Atoi(c.Run.Port)
|
||||
if err != nil {
|
||||
utils.Logger.Fatalf("Failed to parse port as integer: %s", c.Run.Port)
|
||||
}
|
||||
revel_path.HTTPPort = port
|
||||
revel_path, err := model.NewRevelPaths(c.Run.Mode, c.ImportPath, "", model.NewWrappedRevelCallback(nil, c.PackageResolver))
|
||||
if err != nil {
|
||||
return utils.NewBuildIfError(err, "Revel paths")
|
||||
}
|
||||
if c.Run.Port > -1 {
|
||||
revel_path.HTTPPort = c.Run.Port
|
||||
} else {
|
||||
c.Run.Port = revel_path.HTTPPort
|
||||
}
|
||||
|
||||
utils.Logger.Infof("Running %s (%s) in %s mode\n", revel_path.AppName, revel_path.ImportPath, revel_path.RunMode)
|
||||
@@ -145,4 +156,5 @@ func runApp(c *model.CommandConfig) {
|
||||
runMode = revel_path.RunMode
|
||||
}
|
||||
app.Cmd(runMode).Run()
|
||||
return
|
||||
}
|
||||
|
||||
21
revel/run_test.go
Normal file
21
revel/run_test.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// test the commands
|
||||
func TestRun(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
gopath := setup("revel-test-run", a)
|
||||
|
||||
// TODO Testing run
|
||||
|
||||
if !t.Failed() {
|
||||
if err := os.RemoveAll(gopath); err != nil {
|
||||
a.Fail("Failed to remove test path")
|
||||
}
|
||||
}
|
||||
}
|
||||
3
revel/skeleton/.gitignore
vendored
3
revel/skeleton/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
test-results/
|
||||
tmp/
|
||||
routes/
|
||||
@@ -1,43 +0,0 @@
|
||||
# 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).
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
*revel.Controller
|
||||
}
|
||||
|
||||
func (c App) Index() revel.Result {
|
||||
return c.Render()
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
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.BeforeAfterFilter, // Call the before and after filter functions
|
||||
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
|
||||
// There is a full implementation of a CSRF filter in
|
||||
// https://github.com/revel/modules/tree/master/csrf
|
||||
var HeaderFilter = func(c *revel.Controller, fc []revel.Filter) {
|
||||
c.Response.Out.Header().Add("X-Frame-Options", "SAMEORIGIN")
|
||||
c.Response.Out.Header().Add("X-XSS-Protection", "1; mode=block")
|
||||
c.Response.Out.Header().Add("X-Content-Type-Options", "nosniff")
|
||||
c.Response.Out.Header().Add("Referrer-Policy", "strict-origin-when-cross-origin")
|
||||
|
||||
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
|
||||
// }
|
||||
//}
|
||||
@@ -1,21 +0,0 @@
|
||||
{{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" .}}
|
||||
@@ -1,64 +0,0 @@
|
||||
<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>
|
||||
@@ -1,20 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,16 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,18 +0,0 @@
|
||||
{{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}}
|
||||
@@ -1,5 +0,0 @@
|
||||
{{if .DevMode}}
|
||||
{{template "debug.html" .}}
|
||||
{{end}}
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,19 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,223 +0,0 @@
|
||||
################################################################################
|
||||
# Revel configuration file
|
||||
# More info at http://revel.github.io/manual/appconf.html
|
||||
################################################################################
|
||||
|
||||
# Revel build section
|
||||
# This section contains values that are not reloadable
|
||||
################################################################################
|
||||
|
||||
# Comma delimited list of folders that are included with the package, or build commands
|
||||
# If you want to not include folders within these ones prefix the folder with a . to make it hidden
|
||||
package.folders = conf, public, app/views
|
||||
|
||||
|
||||
|
||||
|
||||
# Revel reconfigurable section
|
||||
#
|
||||
################################################################################
|
||||
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
# 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 = eager
|
||||
|
||||
# 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.all.filter.module.app = stdout # Log all loggers for the application to the stdout
|
||||
log.error.nfilter.module.app = stderr # Everything else that logs an error to stderr
|
||||
log.crit.output = stderr # Everything that logs something as critical goes to this
|
||||
|
||||
# Revel request access log
|
||||
# Access log line format:
|
||||
# INFO 21:53:55 static server-engine.go:169: Request Stats ip=127.0.0.1 path=/public/vendors/datatables.net-buttons/js/buttons.html5.min.js method=GET start=2017/08/31 21:53:55 status=200 duration_seconds=0.0002583 section=requestlog
|
||||
log.request.output = stdout
|
||||
|
||||
|
||||
|
||||
################################################################################
|
||||
# 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.warn.output = log/%(app.name)s-warn.json # Log all warn messages to file
|
||||
log.error.output = log/%(app.name)s-error.json # Log all errors to file
|
||||
log.crit.output = log/%(app.name)s-critical.json # Log all critical to file
|
||||
|
||||
# Revel request access log (json format)
|
||||
# Example:
|
||||
# log.request.output = %(app.name)s-request.json
|
||||
log.request.output = log/%(app.name)s-requests.json
|
||||
@@ -1,26 +0,0 @@
|
||||
# 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, this will route any request into the controller path
|
||||
#
|
||||
# **** WARNING ****
|
||||
# Enabling this exposes any controller and function to the web.
|
||||
# ** This is a serious security issue if used online **
|
||||
#
|
||||
# For rapid development uncomment the following to add new controller.action endpoints
|
||||
# without having to add them to the routes table.
|
||||
# * /:controller/:action :controller.:action
|
||||
@@ -1,8 +0,0 @@
|
||||
# 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
|
||||
[DEFAULT]
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 5.5 KiB |
File diff suppressed because one or more lines are too long
4
revel/skeleton/public/js/jquery-2.2.4.min.js
vendored
4
revel/skeleton/public/js/jquery-2.2.4.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,23 +0,0 @@
|
||||
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")
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
)
|
||||
|
||||
var cmdTest = &Command{
|
||||
UsageLine: "test [import path] [run mode] [suite.method]",
|
||||
UsageLine: "test <import path> [<run mode> <suite.method>]",
|
||||
Short: "run all tests from the command-line",
|
||||
Long: `
|
||||
Run all tests for the Revel app named by the given import path.
|
||||
@@ -71,38 +71,38 @@ func updateTestConfig(c *model.CommandConfig, args []string) bool {
|
||||
}
|
||||
|
||||
// Called to test the application
|
||||
func testApp(c *model.CommandConfig) {
|
||||
var err error
|
||||
|
||||
func testApp(c *model.CommandConfig) (err error) {
|
||||
mode := DefaultRunMode
|
||||
if c.Test.Mode != "" {
|
||||
mode = c.Test.Mode
|
||||
}
|
||||
|
||||
// Find and parse app.conf
|
||||
revel_path := model.NewRevelPaths(mode, c.ImportPath, "", model.DoNothingRevelCallback)
|
||||
revel_path, err := model.NewRevelPaths(mode, c.ImportPath, "", model.NewWrappedRevelCallback(nil, c.PackageResolver))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure that the testrunner is loaded in this mode.
|
||||
// todo checkTestRunner()
|
||||
// todo Ensure that the testrunner is loaded in this mode.
|
||||
|
||||
// Create a directory to hold the test result files.
|
||||
resultPath := filepath.Join(revel_path.BasePath, "test-results")
|
||||
if err = os.RemoveAll(resultPath); err != nil {
|
||||
utils.Logger.Errorf("Failed to remove test result directory %s: %s", resultPath, err)
|
||||
return utils.NewBuildError("Failed to remove test result directory ", "path", resultPath, "error", err)
|
||||
}
|
||||
if err = os.Mkdir(resultPath, 0777); err != nil {
|
||||
utils.Logger.Errorf("Failed to create test result directory %s: %s", resultPath, err)
|
||||
return utils.NewBuildError("Failed to create test result directory ", "path", resultPath, "error", err)
|
||||
}
|
||||
|
||||
// Direct all the output into a file in the test-results directory.
|
||||
file, err := os.OpenFile(filepath.Join(resultPath, "app.log"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
utils.Logger.Errorf("Failed to create test result log file: %s", err)
|
||||
return utils.NewBuildError("Failed to create test result log file: ", "error", err)
|
||||
}
|
||||
|
||||
app, reverr := harness.Build(c, revel_path)
|
||||
if reverr != nil {
|
||||
utils.Logger.Errorf("Error building: %s", reverr)
|
||||
return utils.NewBuildIfError(reverr, "Error building: ")
|
||||
}
|
||||
runMode := fmt.Sprintf(`{"mode":"%s","testModeFlag":true, "specialUseFlag":%v}`, app.Paths.RunMode, c.Verbose)
|
||||
if c.HistoricMode {
|
||||
@@ -115,7 +115,7 @@ func testApp(c *model.CommandConfig) {
|
||||
|
||||
// Start the app...
|
||||
if err := cmd.Start(c); err != nil {
|
||||
utils.Logger.Errorf("%s", err)
|
||||
return utils.NewBuildError("Unable to start server", "error", err)
|
||||
}
|
||||
defer cmd.Kill()
|
||||
|
||||
@@ -164,6 +164,8 @@ func testApp(c *model.CommandConfig) {
|
||||
writeResultFile(resultPath, "result.failed", "failed")
|
||||
utils.Logger.Errorf("Some tests failed. See file://%s for results.", resultPath)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Outputs the results to a file
|
||||
@@ -287,7 +289,7 @@ func runTestSuites(paths *model.RevelContainer, baseURL, resultPath string, test
|
||||
err = json.NewDecoder(resp.Body).Decode(&testResult)
|
||||
if err == nil && !testResult.Passed {
|
||||
suiteResult.Passed = false
|
||||
utils.Logger.Error("Test Failed","suite", suite.Name, "test", test.Name)
|
||||
utils.Logger.Error("Test Failed", "suite", suite.Name, "test", test.Name)
|
||||
fmt.Printf(" %s.%s : FAILED\n", suite.Name, test.Name)
|
||||
} else {
|
||||
fmt.Printf(" %s.%s : PASSED\n", suite.Name, test.Name)
|
||||
@@ -306,7 +308,9 @@ func runTestSuites(paths *model.RevelContainer, baseURL, resultPath string, test
|
||||
// Create the result HTML file.
|
||||
suiteResultFilename := filepath.Join(resultPath,
|
||||
fmt.Sprintf("%s.%s.html", suite.Name, strings.ToLower(suiteResultStr)))
|
||||
utils.MustRenderTemplate(suiteResultFilename, resultFilePath, suiteResult)
|
||||
if err := utils.RenderTemplate(suiteResultFilename, resultFilePath, suiteResult); err != nil {
|
||||
utils.Logger.Error("Failed to render template", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
return &failedResults, overallSuccess
|
||||
|
||||
31
revel/test_test.go
Normal file
31
revel/test_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"github.com/revel/cmd/model"
|
||||
"github.com/revel/cmd/revel"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
||||
// test the commands
|
||||
func TestRevelTest(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
gopath := setup("revel-test-test", a)
|
||||
|
||||
t.Run("Test", func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
c := newApp("test-test", model.NEW, nil, a)
|
||||
a.Nil(main.Commands[model.NEW].RunWith(c), "Failed to run test-test")
|
||||
c.Index = model.TEST
|
||||
c.Test.ImportPath = c.ImportPath
|
||||
a.Nil(main.Commands[model.TEST].RunWith(c), "Failed to run test-test")
|
||||
})
|
||||
|
||||
if !t.Failed() {
|
||||
if err := os.RemoveAll(gopath); err != nil {
|
||||
a.Fail("Failed to remove test path")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,67 +12,73 @@ import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/revel/cmd/model"
|
||||
"go/build"
|
||||
"go/token"
|
||||
"go/parser"
|
||||
"go/ast"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"github.com/revel/cmd/utils"
|
||||
"github.com/revel/cmd"
|
||||
"github.com/revel/cmd/model"
|
||||
"github.com/revel/cmd/utils"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var cmdVersion = &Command{
|
||||
UsageLine: "version",
|
||||
UsageLine: "revel version",
|
||||
Short: "displays the Revel Framework and Go version",
|
||||
Long: `
|
||||
Displays the Revel Framework and Go version.
|
||||
|
||||
For example:
|
||||
|
||||
revel version
|
||||
revel version [<application path>]
|
||||
`,
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmdVersion.RunWith = versionApp
|
||||
cmdVersion.UpdateConfig = updateVersionConfig
|
||||
}
|
||||
|
||||
// Update the version
|
||||
func updateVersionConfig(c *model.CommandConfig, args []string) bool {
|
||||
if len(args) > 0 {
|
||||
c.Version.ImportPath = args[0]
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Displays the version of go and Revel
|
||||
func versionApp(c *model.CommandConfig) {
|
||||
func versionApp(c *model.CommandConfig) (err error) {
|
||||
|
||||
var (
|
||||
revelPkg *build.Package
|
||||
err error
|
||||
)
|
||||
if len(c.ImportPath)>0 {
|
||||
appPkg, err := build.Import(c.ImportPath, "", build.FindOnly)
|
||||
if err != nil {
|
||||
utils.Logger.Fatal("Failed to import " + c.ImportPath + " with error:", "error", err)
|
||||
}
|
||||
revelPkg, err = build.Import(model.RevelImportPath, appPkg.Dir, build.FindOnly)
|
||||
} else {
|
||||
revelPkg, err = build.Import(model.RevelImportPath, "" , build.FindOnly)
|
||||
var revelPath, appPath string
|
||||
|
||||
|
||||
appPath, revelPath, err = utils.FindSrcPaths(c.ImportPath, model.RevelImportPath, c.PackageResolver)
|
||||
if err != nil {
|
||||
return utils.NewBuildError("Failed to import "+c.ImportPath+" with error:", "error", err)
|
||||
}
|
||||
revelPath = revelPath + model.RevelImportPath
|
||||
|
||||
fmt.Println("\nRevel Framework")
|
||||
fmt.Println("\nRevel Framework",revelPath, appPath )
|
||||
if err != nil {
|
||||
utils.Logger.Info("Failed to find Revel in GOPATH with error:", "error", err, "gopath", build.Default.GOPATH)
|
||||
fmt.Println("Information not available (not on GOPATH)")
|
||||
} else {
|
||||
utils.Logger.Info("Fullpath to revel", revelPkg.Dir)
|
||||
utils.Logger.Info("Fullpath to revel", "dir", revelPath)
|
||||
fset := token.NewFileSet() // positions are relative to fset
|
||||
|
||||
version, err := ioutil.ReadFile(filepath.Join(revelPkg.Dir, "version.go"))
|
||||
version, err := ioutil.ReadFile(filepath.Join(revelPath, "version.go"))
|
||||
if err != nil {
|
||||
utils.Logger.Errorf("Failed to find Revel version:", "error", err)
|
||||
utils.Logger.Error("Failed to find Revel version:", "error", err, "path", revelPath)
|
||||
}
|
||||
|
||||
// Parse src but stop after processing the imports.
|
||||
f, err := parser.ParseFile(fset, "", version, parser.ParseComments)
|
||||
if err != nil {
|
||||
utils.Logger.Errorf("Failed to parse Revel version error:", "error", err)
|
||||
return utils.NewBuildError("Failed to parse Revel version error:", "error", err)
|
||||
}
|
||||
|
||||
// Print the imports from the file's AST.
|
||||
@@ -96,5 +102,19 @@ func versionApp(c *model.CommandConfig) {
|
||||
fmt.Println("Build Date", cmd.BuildDate)
|
||||
fmt.Println("Minimum Go Version", cmd.MinimumGoVersion)
|
||||
|
||||
fmt.Printf("\n %s %s/%s\n\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
||||
fmt.Printf("Compiled By %s %s/%s\n\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
||||
// Extract the goversion detected
|
||||
if len(c.GoCmd) > 0 {
|
||||
cmd := exec.Command(c.GoCmd, "version")
|
||||
cmd.Stdout = os.Stdout
|
||||
if e := cmd.Start(); e != nil {
|
||||
fmt.Println("Go command error ", e)
|
||||
} else {
|
||||
cmd.Wait()
|
||||
}
|
||||
} else {
|
||||
fmt.Println("Go command not found ")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
41
revel/version_test.go
Normal file
41
revel/version_test.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"github.com/revel/cmd/model"
|
||||
"github.com/revel/cmd/revel"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// test the commands
|
||||
func TestVersion(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
gopath := setup("revel-test-version", a)
|
||||
|
||||
t.Run("Version", func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
c := newApp("version-test", model.NEW, nil, a)
|
||||
a.Nil(main.Commands[model.NEW].RunWith(c), "Check new")
|
||||
c.Build.ImportPath = c.ImportPath
|
||||
c.Build.TargetPath = filepath.Join(gopath, "build-test", "target")
|
||||
a.Nil(main.Commands[model.BUILD].RunWith(c), "Failed to run build")
|
||||
c.Index = model.VERSION
|
||||
c.Version.ImportPath = c.ImportPath
|
||||
a.Nil(main.Commands[model.VERSION].RunWith(c), "Failed to run version-test")
|
||||
})
|
||||
t.Run("Version-Nobuild", func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
c := newApp("version-test2", model.NEW, nil, a)
|
||||
a.Nil(main.Commands[model.NEW].RunWith(c), "Check new")
|
||||
c.Index = model.VERSION
|
||||
c.Version.ImportPath = c.ImportPath
|
||||
a.Nil(main.Commands[model.VERSION].RunWith(c), "Failed to run version-test")
|
||||
})
|
||||
if !t.Failed() {
|
||||
if err := os.RemoveAll(gopath); err != nil {
|
||||
a.Fail("Failed to remove test path")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user