mirror of
https://github.com/kevin-DL/revel-cmd.git
synced 2026-01-11 18:54:31 +00:00
Updated Revel command
Added a check to see if harness had already started, saves a recompile on load Added check to source info for local import renames Removed the go/build check for path and just check existence of the path Formatting updates
This commit is contained in:
@@ -143,8 +143,8 @@ func (cmd AppCmd) Kill() {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
utils.Logger.Error(
|
||||
"Revel app failed to kill process.",
|
||||
utils.Logger.Info(
|
||||
"Revel app already exited.",
|
||||
"processid", cmd.Process.Pid, "error", err,
|
||||
"killerror", cmd.Process.Kill())
|
||||
return
|
||||
|
||||
@@ -16,6 +16,7 @@ package harness
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"time"
|
||||
"go/build"
|
||||
"io"
|
||||
"net"
|
||||
@@ -56,6 +57,8 @@ type Harness struct {
|
||||
paths *model.RevelContainer // The Revel container
|
||||
config *model.CommandConfig // The configuration
|
||||
runMode string // The runmode the harness is running in
|
||||
isError bool // True if harness is in error state
|
||||
ranOnce bool // True app compiled once
|
||||
}
|
||||
|
||||
func (h *Harness) renderError(iw http.ResponseWriter, ir *http.Request, err error) {
|
||||
@@ -202,6 +205,21 @@ func NewHarness(c *model.CommandConfig, paths *model.RevelContainer, runMode str
|
||||
// Refresh method rebuilds the Revel application and run it on the given port.
|
||||
// called by the watcher
|
||||
func (h *Harness) Refresh() (err *utils.SourceError) {
|
||||
t := time.Now();
|
||||
fmt.Println("Changed detected, recompiling")
|
||||
err = h.refresh()
|
||||
if err!=nil && !h.ranOnce && h.useProxy {
|
||||
addr := fmt.Sprintf("%s:%d", h.paths.HTTPAddr, h.paths.HTTPPort)
|
||||
|
||||
fmt.Printf("\nError compiling code, to view error details see proxy running on http://%s\n\n",addr)
|
||||
}
|
||||
|
||||
h.ranOnce = true
|
||||
fmt.Printf("\nTime to recompile %s\n",time.Now().Sub(t).String())
|
||||
return
|
||||
}
|
||||
|
||||
func (h *Harness) refresh() (err *utils.SourceError) {
|
||||
// Allow only one thread to rebuild the process
|
||||
// If multiple requests to rebuild are queued only the last one is executed on
|
||||
// So before a build is started we wait for a second to determine if
|
||||
@@ -281,7 +299,8 @@ func (h *Harness) Run() {
|
||||
paths = append(paths, h.paths.CodePaths...)
|
||||
h.watcher = watcher.NewWatcher(h.paths, false)
|
||||
h.watcher.Listen(h, paths...)
|
||||
h.watcher.Notify()
|
||||
go h.Refresh()
|
||||
// h.watcher.Notify()
|
||||
|
||||
if h.useProxy {
|
||||
go func() {
|
||||
@@ -292,6 +311,7 @@ func (h *Harness) Run() {
|
||||
addr := fmt.Sprintf("%s:%d", h.paths.HTTPAddr, h.paths.HTTPPort)
|
||||
utils.Logger.Infof("Proxy server is listening on %s", addr)
|
||||
|
||||
|
||||
var err error
|
||||
if h.paths.HTTPSsl {
|
||||
err = http.ListenAndServeTLS(
|
||||
@@ -308,13 +328,15 @@ func (h *Harness) Run() {
|
||||
}()
|
||||
|
||||
}
|
||||
// Kill the app on signal.
|
||||
|
||||
// Make a new channel to listen for the interrupt event
|
||||
ch := make(chan os.Signal)
|
||||
signal.Notify(ch, os.Interrupt, os.Kill)
|
||||
<-ch
|
||||
// Kill the app and exit
|
||||
if h.app != nil {
|
||||
h.app.Kill()
|
||||
}
|
||||
<-ch
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"go/token"
|
||||
"strings"
|
||||
"path/filepath"
|
||||
"github.com/revel/cmd/logger"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -31,14 +32,20 @@ func (s *SourceInfoProcessor) processPackage(p *packages.Package) (sourceInfo *m
|
||||
strings.Contains(p.PkgPath, "/tests/")
|
||||
methodMap = map[string][]*model.MethodSpec{}
|
||||
)
|
||||
localImportMap := map[string]string{}
|
||||
log := s.sourceProcessor.log.New("package", p.PkgPath)
|
||||
for _, tree := range p.Syntax {
|
||||
for _, decl := range tree.Decls {
|
||||
|
||||
s.sourceProcessor.packageMap[p.PkgPath] = filepath.Dir(p.Fset.Position(decl.Pos()).Filename)
|
||||
//println("*** checking", p.Fset.Position(decl.Pos()).Filename)
|
||||
if !s.addImport(decl, p, localImportMap, log) {
|
||||
continue
|
||||
}
|
||||
// log.Info("*** checking", p.Fset.Position(decl.Pos()).Filename)
|
||||
spec, found := s.getStructTypeDecl(decl, p.Fset)
|
||||
if found {
|
||||
if isController || isTest {
|
||||
controllerSpec := s.getControllerSpec(spec, p)
|
||||
controllerSpec := s.getControllerSpec(spec, p, localImportMap)
|
||||
sourceInfo.StructSpecs = append(sourceInfo.StructSpecs, controllerSpec)
|
||||
}
|
||||
} else {
|
||||
@@ -56,7 +63,7 @@ func (s *SourceInfoProcessor) processPackage(p *packages.Package) (sourceInfo *m
|
||||
// return one result
|
||||
if m, receiver := s.getControllerFunc(funcDecl, p); m != nil {
|
||||
methodMap[receiver] = append(methodMap[receiver], m)
|
||||
s.sourceProcessor.log.Info("Added method map to ", "receiver", receiver, "method", m.Name)
|
||||
log.Info("Added method map to ", "receiver", receiver, "method", m.Name)
|
||||
}
|
||||
}
|
||||
// Check for validation
|
||||
@@ -271,7 +278,7 @@ func (s *SourceInfoProcessor) getControllerFunc(funcDecl *ast.FuncDecl, p *packa
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *SourceInfoProcessor) getControllerSpec(spec *ast.TypeSpec, p *packages.Package) (controllerSpec *model.TypeInfo) {
|
||||
func (s *SourceInfoProcessor) getControllerSpec(spec *ast.TypeSpec, p *packages.Package, localImportMap map[string]string) (controllerSpec *model.TypeInfo) {
|
||||
structType := spec.Type.(*ast.StructType)
|
||||
|
||||
// At this point we know it's a type declaration for a struct.
|
||||
@@ -330,11 +337,14 @@ func (s *SourceInfoProcessor) getControllerSpec(spec *ast.TypeSpec, p *packages.
|
||||
importPath = p.PkgPath
|
||||
} else {
|
||||
var ok bool
|
||||
if importPath, ok = localImportMap[pkgName]; !ok {
|
||||
log.Debug("Debug: Unusual, failed to find package locally ", "package", pkgName, "type", typeName, "map", s.sourceProcessor.importMap, "usedin", )
|
||||
if importPath, ok = s.sourceProcessor.importMap[pkgName]; !ok {
|
||||
log.Error("Error: Failed to find import path for ", "package", pkgName, "type", typeName, "map", s.sourceProcessor.importMap, "usedin", )
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
controllerSpec.EmbeddedTypes = append(controllerSpec.EmbeddedTypes, &model.EmbeddedTypeName{
|
||||
ImportPath: importPath,
|
||||
@@ -378,3 +388,36 @@ func (s *SourceInfoProcessor) getFuncName(funcDecl *ast.FuncDecl) string {
|
||||
}
|
||||
return prefix + funcDecl.Name.Name
|
||||
}
|
||||
func (s *SourceInfoProcessor) addImport(decl ast.Decl, p *packages.Package, localImportMap map[string]string, log logger.MultiLogger) (shouldContinue bool) {
|
||||
shouldContinue = true
|
||||
genDecl, ok := decl.(*ast.GenDecl)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if genDecl.Tok == token.IMPORT {
|
||||
shouldContinue = false
|
||||
for _, spec := range genDecl.Specs {
|
||||
importSpec := spec.(*ast.ImportSpec)
|
||||
//fmt.Printf("*** import specification %#v\n", importSpec)
|
||||
var pkgAlias string
|
||||
if importSpec.Name != nil {
|
||||
pkgAlias = importSpec.Name.Name
|
||||
if pkgAlias == "_" {
|
||||
continue
|
||||
}
|
||||
}
|
||||
quotedPath := importSpec.Path.Value // e.g. "\"sample/app/models\""
|
||||
fullPath := quotedPath[1 : len(quotedPath) - 1] // Remove the quotes
|
||||
if pkgAlias == "" {
|
||||
pkgAlias = fullPath
|
||||
if index := strings.LastIndex(pkgAlias, "/"); index > 0 {
|
||||
pkgAlias = pkgAlias[index + 1:]
|
||||
}
|
||||
}
|
||||
localImportMap[pkgAlias] = fullPath
|
||||
}
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -43,6 +43,7 @@ func NewSourceProcessor(revelContainer *model.RevelContainer) *SourceProcessor {
|
||||
s.sourceInfoProcessor = NewSourceInfoProcessor(s)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *SourceProcessor) parse() (compileError error) {
|
||||
if compileError = s.addPackages(); compileError != nil {
|
||||
return
|
||||
@@ -71,11 +72,15 @@ func (s *SourceProcessor) parse() (compileError error) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Using the packages.Load function load all the packages and type specifications (forces compile).
|
||||
// this sets the SourceProcessor.packageList []*packages.Package
|
||||
func (s *SourceProcessor) addPackages() (err error) {
|
||||
allPackages := []string{s.revelContainer.ImportPath + "/...", model.RevelImportPath + "/..."}
|
||||
for _, module := range s.revelContainer.ModulePathMap {
|
||||
allPackages = append(allPackages, module.ImportPath + "/...") // +"/app/controllers/...")
|
||||
}
|
||||
s.log.Info("Reading packages", "packageList", allPackages)
|
||||
//allPackages = []string{s.revelContainer.ImportPath + "/..."} //+"/app/controllers/..."}
|
||||
|
||||
config := &packages.Config{
|
||||
|
||||
@@ -11,9 +11,7 @@ import (
|
||||
"github.com/revel/cmd/harness"
|
||||
"github.com/revel/cmd/model"
|
||||
"github.com/revel/cmd/utils"
|
||||
"go/build"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var cmdRun = &Command{
|
||||
@@ -116,10 +114,7 @@ func updateRunConfig(c *model.CommandConfig, args []string) bool {
|
||||
|
||||
// Returns true if this is an absolute path or a relative gopath
|
||||
func runIsImportPath(pathToCheck string) bool {
|
||||
if _, err := build.Import(pathToCheck, "", build.FindOnly); err == nil {
|
||||
return true
|
||||
}
|
||||
return filepath.IsAbs(pathToCheck)
|
||||
return utils.DirExists(pathToCheck)
|
||||
}
|
||||
|
||||
// Called to run the app
|
||||
|
||||
@@ -364,8 +364,8 @@ func findSrcPaths(appPath string, packagesList []string) (sourcePathsmap map[str
|
||||
log.Info("Found package", "package", pck.ID)
|
||||
if pck.ID == packageName {
|
||||
if pck.Errors != nil && len(pck.Errors) > 0 {
|
||||
log.Info("Error ", "count", len(pck.Errors), "App Import Path", pck.ID, "errors", pck.Errors)
|
||||
continue
|
||||
log.Error("Error ", "count", len(pck.Errors), "App Import Path", pck.ID, "filesystem path", pck.PkgPath, "errors", pck.Errors)
|
||||
// continue
|
||||
|
||||
}
|
||||
//a,_ := pck.MarshalJSON()
|
||||
|
||||
@@ -52,10 +52,10 @@ type Watcher struct {
|
||||
// Creates a new watched based on the container
|
||||
func NewWatcher(paths *model.RevelContainer, eagerRefresh bool) *Watcher {
|
||||
return &Watcher{
|
||||
forceRefresh: true,
|
||||
forceRefresh: false,
|
||||
lastError: -1,
|
||||
paths: paths,
|
||||
refreshTimerMS: time.Duration(paths.Config.IntDefault("watch.rebuild.delay", 10)),
|
||||
refreshTimerMS: time.Duration(paths.Config.IntDefault("watch.rebuild.delay", 1000)),
|
||||
eagerRefresh: eagerRefresh ||
|
||||
paths.DevMode &&
|
||||
paths.Config.BoolDefault("watch", true) &&
|
||||
@@ -205,7 +205,8 @@ func (w *Watcher) Notify() *utils.SourceError {
|
||||
break
|
||||
}
|
||||
|
||||
utils.Logger.Info("Watcher:Notify refresh state", "Current Index", i, " last error index", w.lastError)
|
||||
utils.Logger.Info("Watcher:Notify refresh state", "Current Index", i, " last error index", w.lastError,
|
||||
"force", w.forceRefresh, "refresh", refresh, "lastError", w.lastError == i)
|
||||
if w.forceRefresh || refresh || w.lastError == i {
|
||||
var err *utils.SourceError
|
||||
if w.serial {
|
||||
@@ -292,15 +293,3 @@ func (w *Watcher) rebuildRequired(ev fsnotify.Event, listener Listener) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
var WatchFilter = func(c *Controller, fc []Filter) {
|
||||
if MainWatcher != nil {
|
||||
err := MainWatcher.Notify()
|
||||
if err != nil {
|
||||
c.Result = c.RenderError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
fc[0](c, fc[1:])
|
||||
}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user