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:
NotZippy
2018-09-27 21:08:40 -07:00
parent 01ccd695d4
commit f4fb2ec091
65 changed files with 2014 additions and 1281 deletions

View File

@@ -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
View 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")
}
}
}

View File

@@ -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
View 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
View 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
}

View File

@@ -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
View 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")
}
}
}

View File

@@ -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
View 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")
}
}
}

View File

@@ -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")
}

View File

@@ -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
View 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")
}
}
}

View File

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

View File

@@ -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).

View File

@@ -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()
}

View File

@@ -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
// }
//}

View File

@@ -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" .}}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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}}

View File

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

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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.

Before

Width:  |  Height:  |  Size: 5.5 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -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")
}

View File

@@ -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
View 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")
}
}
}

View File

@@ -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
View 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")
}
}
}