mirror of
https://github.com/kevin-DL/revel-cmd.git
synced 2026-01-21 22:54:58 +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:
@@ -61,28 +61,30 @@ func NewAppCmd(binPath string, port int, runMode string, paths *model.RevelConta
|
||||
|
||||
// Start the app server, and wait until it is ready to serve requests.
|
||||
func (cmd AppCmd) Start(c *model.CommandConfig) error {
|
||||
listeningWriter := &startupListeningWriter{os.Stdout, make(chan bool),c}
|
||||
listeningWriter := &startupListeningWriter{os.Stdout, make(chan bool), c}
|
||||
cmd.Stdout = listeningWriter
|
||||
utils.Logger.Info("Exec app:", "path", cmd.Path, "args", cmd.Args)
|
||||
utils.Logger.Info("Exec app:", "path", cmd.Path, "args", cmd.Args, "dir", cmd.Dir, "env", cmd.Env)
|
||||
utils.CmdInit(cmd.Cmd, c.AppPath)
|
||||
if err := cmd.Cmd.Start(); err != nil {
|
||||
utils.Logger.Fatal("Error running:", "error", err)
|
||||
}
|
||||
|
||||
select {
|
||||
case exitState := <-cmd.waitChan():
|
||||
println("Revel proxy is listening, point your browser to :", c.Run.Port)
|
||||
return errors.New("revel/harness: app died reason: " + exitState)
|
||||
|
||||
case <-time.After(60 * time.Second):
|
||||
println("Revel proxy is listening, point your browser to :", c.Run.Port)
|
||||
utils.Logger.Error("Killing revel server process did not respond after wait timeout.", "processid", cmd.Process.Pid)
|
||||
cmd.Kill()
|
||||
return errors.New("revel/harness: app timed out")
|
||||
|
||||
case <-listeningWriter.notifyReady:
|
||||
println("Revel proxy is listening, point your browser to :", c.Run.Port)
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO remove this unreachable code and document it
|
||||
panic("Impossible")
|
||||
}
|
||||
|
||||
// Run the app server inline. Never returns.
|
||||
@@ -111,7 +113,7 @@ func (cmd AppCmd) waitChan() <-chan string {
|
||||
_ = cmd.Wait()
|
||||
state := cmd.ProcessState
|
||||
exitStatus := " unknown "
|
||||
if state!=nil {
|
||||
if state != nil {
|
||||
exitStatus = state.String()
|
||||
}
|
||||
|
||||
@@ -126,7 +128,7 @@ func (cmd AppCmd) waitChan() <-chan string {
|
||||
type startupListeningWriter struct {
|
||||
dest io.Writer
|
||||
notifyReady chan bool
|
||||
c *model.CommandConfig
|
||||
c *model.CommandConfig
|
||||
}
|
||||
|
||||
func (w *startupListeningWriter) Write(p []byte) (int, error) {
|
||||
|
||||
@@ -36,12 +36,12 @@ func (c ByString) Less(i, j int) bool { return c[i].String() < c[j].String() }
|
||||
// 2. Run the appropriate "go build" command.
|
||||
// Requires that revel.Init has been called previously.
|
||||
// Returns the path to the built binary, and an error if there was a problem building it.
|
||||
func Build(c *model.CommandConfig, paths *model.RevelContainer) (app *App, compileError *utils.Error) {
|
||||
func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err error) {
|
||||
// First, clear the generated files (to avoid them messing with ProcessSource).
|
||||
cleanSource(paths, "tmp", "routes")
|
||||
|
||||
sourceInfo, compileError := parser.ProcessSource(paths)
|
||||
if compileError != nil {
|
||||
sourceInfo, err := parser.ProcessSource(paths)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -68,9 +68,15 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (app *App, compi
|
||||
// without being the main thread
|
||||
cleanSource(paths, "tmp", "routes")
|
||||
|
||||
genSource(paths, "tmp", "main.go", RevelMainTemplate, templateArgs)
|
||||
genSource(paths, filepath.Join("tmp", "run"), "run.go", RevelRunTemplate, templateArgs)
|
||||
genSource(paths, "routes", "routes.go", RevelRoutesTemplate, templateArgs)
|
||||
if err = genSource(paths, "tmp", "main.go", RevelMainTemplate, templateArgs); err != nil {
|
||||
return
|
||||
}
|
||||
if err = genSource(paths, filepath.Join("tmp", "run"), "run.go", RevelRunTemplate, templateArgs); err != nil {
|
||||
return
|
||||
}
|
||||
if err = genSource(paths, "routes", "routes.go", RevelRoutesTemplate, templateArgs); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Read build config.
|
||||
buildTags := paths.Config.StringDefault("build.tags", "")
|
||||
@@ -102,23 +108,9 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (app *App, compi
|
||||
}
|
||||
}
|
||||
|
||||
var depPath string
|
||||
if useVendor {
|
||||
utils.Logger.Info("Vendor folder detected, scanning for deps in path")
|
||||
depPath, err = exec.LookPath("dep")
|
||||
if err != nil {
|
||||
// Do not halt build unless a new package needs to be imported
|
||||
utils.Logger.Warn("Build: `dep` executable not found in PATH, but vendor folder detected." +
|
||||
"Packages can only be added automatically to the vendor folder using the `dep` tool. " +
|
||||
"You can install the `dep` tool by doing a `go get -u github.com/golang/dep/cmd/dep`")
|
||||
}
|
||||
} else {
|
||||
utils.Logger.Info("No vendor folder detected, not using dependency manager to import files")
|
||||
}
|
||||
|
||||
pkg, err := build.Default.Import(paths.ImportPath, "", build.FindOnly)
|
||||
if err != nil {
|
||||
utils.Logger.Fatal("Failure importing", "path", paths.ImportPath)
|
||||
return
|
||||
}
|
||||
|
||||
// Binary path is a combination of $GOBIN/revel.d directory, app's import path and its name.
|
||||
@@ -191,6 +183,7 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (app *App, compi
|
||||
buildCmd.Env = append(os.Environ(),
|
||||
"GOPATH="+gopath,
|
||||
)
|
||||
utils.CmdInit(buildCmd, c.AppPath)
|
||||
utils.Logger.Info("Exec:", "args", buildCmd.Args)
|
||||
output, err := buildCmd.CombinedOutput()
|
||||
|
||||
@@ -220,32 +213,9 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (app *App, compi
|
||||
return nil, newCompileError(paths, output)
|
||||
}
|
||||
gotten[pkgName] = struct{}{}
|
||||
|
||||
// Execute "go get <pkg>"
|
||||
// Or dep `dep ensure -add <pkg>` if it is there
|
||||
var getCmd *exec.Cmd
|
||||
if useVendor {
|
||||
if depPath == "" {
|
||||
utils.Logger.Warn("Build: Vendor folder found, but the `dep` tool was not found, " +
|
||||
"if you use a different vendoring (package management) tool please add the following packages by hand, " +
|
||||
"or install the `dep` tool into your gopath by doing a `go get -u github.com/golang/dep/cmd/dep`. " +
|
||||
"For more information and usage of the tool please see http://github.com/golang/dep")
|
||||
for _, pkg := range matches {
|
||||
utils.Logger.Warn("Missing package", "package", pkg[1])
|
||||
}
|
||||
}
|
||||
getCmd = exec.Command(depPath, "ensure", "-add", pkgName)
|
||||
getCmd.Dir = paths.AppPath
|
||||
|
||||
} else {
|
||||
getCmd = exec.Command(goPath, "get", pkgName)
|
||||
}
|
||||
utils.Logger.Info("Exec:", "args", getCmd.Args)
|
||||
getOutput, err := getCmd.CombinedOutput()
|
||||
if err != nil {
|
||||
utils.Logger.Error("Build failed", "message", stOutput, "error", err)
|
||||
utils.Logger.Error("Failed to fetch the output", "getOutput", string(getOutput))
|
||||
return nil, newCompileError(paths, output)
|
||||
if err := c.PackageResolver(pkgName); err != nil {
|
||||
utils.Logger.Error("Unable to resolve package", "package", pkgName, "error", err)
|
||||
return nil, newCompileError(paths, []byte(err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,12 +306,9 @@ func cleanDir(paths *model.RevelContainer, dir string) {
|
||||
|
||||
// genSource renders the given template to produce source code, which it writes
|
||||
// to the given directory and file.
|
||||
func genSource(paths *model.RevelContainer, dir, filename, templateSource string, args map[string]interface{}) {
|
||||
func genSource(paths *model.RevelContainer, dir, filename, templateSource string, args map[string]interface{}) error {
|
||||
|
||||
err := utils.MustGenerateTemplate(filepath.Join(paths.AppPath, dir, filename), templateSource, args)
|
||||
if err != nil {
|
||||
utils.Logger.Fatal("Failed to generate template for source file", "error", err)
|
||||
}
|
||||
return utils.GenerateTemplate(filepath.Join(paths.AppPath, dir, filename), templateSource, args)
|
||||
}
|
||||
|
||||
// Looks through all the method args and returns a set of unique import paths
|
||||
@@ -433,7 +400,8 @@ func newCompileError(paths *model.RevelContainer, output []byte) *utils.Error {
|
||||
// Extract the paths from the gopaths, and search for file there first
|
||||
gopaths := filepath.SplitList(build.Default.GOPATH)
|
||||
for _, gp := range gopaths {
|
||||
newPath := filepath.Join(gp, relFilename)
|
||||
newPath := filepath.Join(gp,"src", paths.ImportPath, relFilename)
|
||||
println(newPath)
|
||||
if utils.Exists(newPath) {
|
||||
return newPath
|
||||
}
|
||||
@@ -443,6 +411,7 @@ func newCompileError(paths *model.RevelContainer, output []byte) *utils.Error {
|
||||
return newPath
|
||||
}
|
||||
|
||||
|
||||
// Read the source for the offending file.
|
||||
var (
|
||||
relFilename = string(errorMatch[1]) // e.g. "src/revel/sample/app/controllers/app.go"
|
||||
@@ -467,7 +436,7 @@ func newCompileError(paths *model.RevelContainer, output []byte) *utils.Error {
|
||||
fileStr, err := utils.ReadLines(absFilename)
|
||||
if err != nil {
|
||||
compileError.MetaError = absFilename + ": " + err.Error()
|
||||
utils.Logger.Error("Unable to readlines "+compileError.MetaError, "error", err)
|
||||
utils.Logger.Info("Unable to readlines "+compileError.MetaError, "error", err)
|
||||
return compileError
|
||||
}
|
||||
|
||||
|
||||
@@ -31,9 +31,9 @@ import (
|
||||
"github.com/revel/cmd/model"
|
||||
"github.com/revel/cmd/utils"
|
||||
"github.com/revel/cmd/watcher"
|
||||
"sync"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -63,31 +63,31 @@ func (h *Harness) renderError(iw http.ResponseWriter, ir *http.Request, err erro
|
||||
// 1) Application/views/errors
|
||||
// 2) revel_home/views/errors
|
||||
// 3) views/errors
|
||||
if err==nil {
|
||||
if err == nil {
|
||||
utils.Logger.Panic("Caller passed in a nil error")
|
||||
}
|
||||
templateSet := template.New("__root__")
|
||||
seekViewOnPath:=func(view string) (path string) {
|
||||
seekViewOnPath := func(view string) (path string) {
|
||||
path = filepath.Join(h.paths.ViewsPath, "errors", view)
|
||||
if !utils.Exists(path) {
|
||||
path = filepath.Join(h.paths.RevelPath, "templates", "errors", view)
|
||||
}
|
||||
|
||||
data,err := ioutil.ReadFile(path)
|
||||
if err!=nil {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
utils.Logger.Error("Unable to read template file", path)
|
||||
}
|
||||
_,err = templateSet.New("errors/"+view).Parse(string(data))
|
||||
if err!=nil {
|
||||
_, err = templateSet.New("errors/" + view).Parse(string(data))
|
||||
if err != nil {
|
||||
utils.Logger.Error("Unable to parse template file", path)
|
||||
}
|
||||
return
|
||||
}
|
||||
target := []string{seekViewOnPath("500.html"),seekViewOnPath("500-dev.html")}
|
||||
target := []string{seekViewOnPath("500.html"), seekViewOnPath("500-dev.html")}
|
||||
if !utils.Exists(target[0]) {
|
||||
fmt.Fprintf(iw, "Target template not found not found %s<br />\n", target[0])
|
||||
fmt.Fprintf(iw, "An error ocurred %s", err.Error())
|
||||
return
|
||||
return
|
||||
}
|
||||
var revelError *utils.Error
|
||||
switch e := err.(type) {
|
||||
@@ -108,16 +108,11 @@ func (h *Harness) renderError(iw http.ResponseWriter, ir *http.Request, err erro
|
||||
viewArgs["DevMode"] = h.paths.DevMode
|
||||
viewArgs["Error"] = revelError
|
||||
|
||||
|
||||
|
||||
// Render the template from the file
|
||||
err = templateSet.ExecuteTemplate(iw,"errors/500.html",viewArgs)
|
||||
if err!=nil {
|
||||
utils.Logger.Error("Failed to execute","error",err)
|
||||
err = templateSet.ExecuteTemplate(iw, "errors/500.html", viewArgs)
|
||||
if err != nil {
|
||||
utils.Logger.Error("Failed to execute", "error", err)
|
||||
}
|
||||
fmt.Println("template ",templateSet.Templates()[0].Name(), templateSet.Templates()[1].Name())
|
||||
//utils.MustRenderTemplateToStream(iw,target, viewArgs)
|
||||
|
||||
}
|
||||
|
||||
// ServeHTTP handles all requests.
|
||||
@@ -192,7 +187,6 @@ func NewHarness(c *model.CommandConfig, paths *model.RevelContainer, runMode str
|
||||
useProxy: !noProxy,
|
||||
config: c,
|
||||
runMode: runMode,
|
||||
|
||||
}
|
||||
|
||||
if paths.HTTPSsl {
|
||||
@@ -219,9 +213,17 @@ func (h *Harness) Refresh() (err *utils.Error) {
|
||||
}
|
||||
|
||||
utils.Logger.Info("Rebuild Called")
|
||||
h.app, err = Build(h.config, h.paths)
|
||||
if err != nil {
|
||||
utils.Logger.Error("Build detected an error", "error", err)
|
||||
var newErr error
|
||||
h.app, newErr = Build(h.config, h.paths)
|
||||
if newErr != nil {
|
||||
utils.Logger.Error("Build detected an error", "error", newErr)
|
||||
if castErr, ok := newErr.(*utils.Error); ok {
|
||||
return castErr
|
||||
}
|
||||
err = &utils.Error{
|
||||
Title: "App failed to start up",
|
||||
Description: err.Error(),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -269,7 +271,7 @@ func (h *Harness) Run() {
|
||||
if h.useProxy {
|
||||
go func() {
|
||||
// Check the port to start on a random port
|
||||
if h.paths.HTTPPort==0 {
|
||||
if h.paths.HTTPPort == 0 {
|
||||
h.paths.HTTPPort = getFreePort()
|
||||
}
|
||||
addr := fmt.Sprintf("%s:%d", h.paths.HTTPAddr, h.paths.HTTPPort)
|
||||
|
||||
Reference in New Issue
Block a user