mirror of
https://github.com/kevin-DL/revel-cmd.git
synced 2026-01-11 18:54:31 +00:00
24
.travis.yml
24
.travis.yml
@@ -47,19 +47,25 @@ script:
|
||||
#- revel package my/testapp prod
|
||||
|
||||
# Ensure the new-app flow works (plus the other commands).
|
||||
- revel new --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v
|
||||
- revel test --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v
|
||||
- revel clean --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v
|
||||
- revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v -t build/testapp2
|
||||
- revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v -t build/testapp2 -m prod
|
||||
- revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v
|
||||
- revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v -m prod
|
||||
- revel new --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp2 --package revelframework.com -v
|
||||
- revel test --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp2 -v
|
||||
- revel clean --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp2 -v
|
||||
- revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp2 -v -t build/testapp2
|
||||
- revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp2 -v -t build/testapp2 -m prod
|
||||
- revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp2 -v
|
||||
- revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp2 -v -m prod
|
||||
|
||||
- export INITIALWD=$PWD
|
||||
# Check build works with no-vendor flag
|
||||
- cd $GOPATH
|
||||
- export GO111MODULE=auto
|
||||
- revel new -a my/testapp2 --no-vendor
|
||||
- revel test -a my/testapp2
|
||||
- revel new -a my/testapp2 --no-vendor -v
|
||||
- revel test -a my/testapp2 -v
|
||||
|
||||
# Check non verbose build, outside of GO path
|
||||
- cd $INITIALWD
|
||||
- revel new --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp3 --package revelframework.com
|
||||
- revel test --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@$REVEL_BRANCH" -a my/testapp3
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
|
||||
@@ -106,7 +106,7 @@ func (cmd AppCmd) Kill() {
|
||||
if cmd.Cmd != nil && (cmd.ProcessState == nil || !cmd.ProcessState.Exited()) {
|
||||
// Windows appears to send the kill to all threads, shutting down the
|
||||
// server before this can, this check will ensure the process is still running
|
||||
if _, err := os.FindProcess(int(cmd.Process.Pid));err!=nil {
|
||||
if _, err := os.FindProcess(int(cmd.Process.Pid)); err != nil {
|
||||
// Server has already exited
|
||||
utils.Logger.Info("Server not running revel server pid", "pid", cmd.Process.Pid)
|
||||
return
|
||||
@@ -143,9 +143,9 @@ func (cmd AppCmd) Kill() {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
utils.Logger.Error(
|
||||
"Revel app failed to kill process.",
|
||||
"processid", cmd.Process.Pid,"error",err,
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -174,8 +174,10 @@ func (c *CommandConfig) initAppFolder() (err error) {
|
||||
|
||||
// Use app folder to read the go.mod if it exists and extract the package information
|
||||
goModFile := filepath.Join(appFolder, "go.mod")
|
||||
utils.Logger.Info("Checking gomod, extracting from file", "path", goModFile,"exists", utils.Exists(goModFile))
|
||||
if utils.Exists(goModFile) {
|
||||
c.Vendored = true
|
||||
utils.Logger.Info("Found go mod, extracting from file", "path", goModFile)
|
||||
file, err := ioutil.ReadFile(goModFile)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -220,7 +222,7 @@ func (c *CommandConfig) initAppFolder() (err error) {
|
||||
c.AppPath = appFolder
|
||||
}
|
||||
|
||||
utils.Logger.Info("Set application path", "path", c.AppPath)
|
||||
utils.Logger.Info("Set application path", "path", c.AppPath, "vendored",c.Vendored, "importpath",c.ImportPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -233,6 +235,7 @@ func (c *CommandConfig) InitPackageResolver() {
|
||||
c.PackageResolver = func(pkgName string) error {
|
||||
utils.Logger.Info("Request for package ", "package", pkgName, "use vendor", c.Vendored)
|
||||
var getCmd *exec.Cmd
|
||||
print("Downloading related packages ...")
|
||||
if c.Vendored {
|
||||
getCmd = exec.Command(c.GoCmd, "mod", "tidy")
|
||||
} else {
|
||||
@@ -246,6 +249,7 @@ func (c *CommandConfig) InitPackageResolver() {
|
||||
if err != nil {
|
||||
utils.Logger.Error("Failed to import package", "error", err, "gopath", build.Default.GOPATH, "GO-ROOT", build.Default.GOROOT, "output", string(output))
|
||||
}
|
||||
println(" completed.")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -57,7 +57,6 @@ func (s *SourceInfo) TypesThatEmbed(targetType, packageFilter string) (filtered
|
||||
|
||||
// Look through the embedded types to see if the current type is among them.
|
||||
for _, embeddedType := range spec.EmbeddedTypes {
|
||||
|
||||
// If so, add this type's simple name to the nodeQueue, and its spec to
|
||||
// the filtered list.
|
||||
if typeSimpleName == embeddedType.String() {
|
||||
@@ -111,6 +110,7 @@ func (s *SourceInfo) TypesThatEmbed(targetType, packageFilter string) (filtered
|
||||
// ControllerSpecs returns the all the controllers that embeds
|
||||
// `revel.Controller`
|
||||
func (s *SourceInfo) ControllerSpecs() []*TypeInfo {
|
||||
utils.Logger.Info("Scanning controller specifications for types ","typePath",RevelImportPath + ".Controller", "speclen",len(s.controllerSpecs))
|
||||
if s.controllerSpecs == nil {
|
||||
s.controllerSpecs = s.TypesThatEmbed(RevelImportPath + ".Controller", "controllers")
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"go/token"
|
||||
"strings"
|
||||
"path/filepath"
|
||||
"github.com/revel/cmd/logger"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -31,14 +32,21 @@ 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)
|
||||
log.Info("Processing package")
|
||||
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
|
||||
}
|
||||
spec, found := s.getStructTypeDecl(decl, p.Fset)
|
||||
//log.Info("Checking file","filename", p.Fset.Position(decl.Pos()).Filename,"found",found)
|
||||
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 +64,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 +279,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.
|
||||
@@ -282,6 +290,7 @@ func (s *SourceInfoProcessor) getControllerSpec(spec *ast.TypeSpec, p *packages.
|
||||
ImportPath: p.PkgPath,
|
||||
PackageName: p.Name,
|
||||
}
|
||||
log := s.sourceProcessor.log.New("file", p.Fset.Position(spec.Pos()).Filename, "position", p.Fset.Position(spec.Pos()).Line)
|
||||
for _, field := range structType.Fields.List {
|
||||
// If field.Names is set, it's not an embedded type.
|
||||
if field.Names != nil {
|
||||
@@ -329,9 +338,12 @@ func (s *SourceInfoProcessor) getControllerSpec(spec *ast.TypeSpec, p *packages.
|
||||
importPath = p.PkgPath
|
||||
} else {
|
||||
var ok bool
|
||||
if importPath, ok = s.sourceProcessor.importMap[pkgName]; !ok {
|
||||
s.sourceProcessor.log.Error("Error: Failed to find import path for ", "package", pkgName, "type", typeName, "map", s.sourceProcessor.importMap)
|
||||
continue
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,4 +388,37 @@ func (s *SourceInfoProcessor) getFuncName(funcDecl *ast.FuncDecl) string {
|
||||
prefix += "."
|
||||
}
|
||||
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
|
||||
}
|
||||
@@ -1,15 +1,18 @@
|
||||
package parser2
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"github.com/revel/cmd/model"
|
||||
"golang.org/x/tools/go/packages"
|
||||
"github.com/revel/cmd/utils"
|
||||
"errors"
|
||||
|
||||
"go/parser"
|
||||
"strings"
|
||||
"github.com/revel/cmd/logger"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/scanner"
|
||||
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -33,10 +36,6 @@ func ProcessSource(revelContainer *model.RevelContainer) (sourceInfo *model.Sour
|
||||
processor.log.Infof("From parsers : Structures:%d InitImports:%d ValidationKeys:%d %v", len(sourceInfo.StructSpecs), len(sourceInfo.InitImportPaths), len(sourceInfo.ValidationKeys), sourceInfo.PackageMap)
|
||||
}
|
||||
|
||||
if false {
|
||||
compileError = errors.New("Incompleted")
|
||||
utils.Logger.Panic("Not implemented")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -45,16 +44,20 @@ func NewSourceProcessor(revelContainer *model.RevelContainer) *SourceProcessor {
|
||||
s.sourceInfoProcessor = NewSourceInfoProcessor(s)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *SourceProcessor) parse() (compileError error) {
|
||||
print("Parsing packages, (may require download if not cached)...")
|
||||
if compileError = s.addPackages(); compileError != nil {
|
||||
return
|
||||
}
|
||||
println(" Completed")
|
||||
if compileError = s.addImportMap(); compileError != nil {
|
||||
return
|
||||
}
|
||||
if compileError = s.addSourceInfo(); compileError != nil {
|
||||
return
|
||||
}
|
||||
|
||||
s.sourceInfo.PackageMap = map[string]string{}
|
||||
getImportFromMap := func(packagePath string) string {
|
||||
for path := range s.packageMap {
|
||||
@@ -73,11 +76,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}
|
||||
allPackages := []string{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{
|
||||
@@ -102,9 +109,115 @@ func (s *SourceProcessor) addPackages() (err error) {
|
||||
Dir:s.revelContainer.AppPath,
|
||||
}
|
||||
s.packageList, err = packages.Load(config, allPackages...)
|
||||
s.log.Info("Loaded packages ", "len results", len(s.packageList), "error", err)
|
||||
s.log.Info("Loaded modules ", "len results", len(s.packageList), "error", err)
|
||||
|
||||
|
||||
// Now process the files in the aap source folder s.revelContainer.ImportPath + "/...",
|
||||
err = utils.Walk(s.revelContainer.AppPath, s.processPath)
|
||||
s.log.Info("Loaded apps and modules ", "len results", len(s.packageList), "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
// This callback is used to build the packages for the "app" package. This allows us to
|
||||
// parse the source files without doing a full compile on them
|
||||
// This callback only processes folders, so any files passed to this will return a nil
|
||||
func (s *SourceProcessor) processPath(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
s.log.Error("Error scanning app source:", "error", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Ignore files and folders not marked tmp (since those are generated)
|
||||
if !info.IsDir() || info.Name() == "tmp" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Real work for processing the folder
|
||||
pkgImportPath := s.revelContainer.ImportPath
|
||||
appPath := s.revelContainer.BasePath
|
||||
if appPath != path {
|
||||
pkgImportPath = s.revelContainer.ImportPath + "/" + filepath.ToSlash(path[len(appPath)+1:])
|
||||
}
|
||||
// Parse files within the path.
|
||||
var pkgMap map[string]*ast.Package
|
||||
fset := token.NewFileSet()
|
||||
pkgMap, err = parser.ParseDir(
|
||||
fset,
|
||||
path,
|
||||
func(f os.FileInfo) bool {
|
||||
return !f.IsDir() && !strings.HasPrefix(f.Name(), ".") && strings.HasSuffix(f.Name(), ".go")
|
||||
},
|
||||
0)
|
||||
|
||||
if err != nil {
|
||||
if errList, ok := err.(scanner.ErrorList); ok {
|
||||
var pos = errList[0].Pos
|
||||
newError := &utils.SourceError{
|
||||
SourceType: ".go source",
|
||||
Title: "Go Compilation Error",
|
||||
Path: pos.Filename,
|
||||
Description: errList[0].Msg,
|
||||
Line: pos.Line,
|
||||
Column: pos.Column,
|
||||
SourceLines: utils.MustReadLines(pos.Filename),
|
||||
}
|
||||
|
||||
errorLink := s.revelContainer.Config.StringDefault("error.link", "")
|
||||
if errorLink != "" {
|
||||
newError.SetLink(errorLink)
|
||||
}
|
||||
return newError
|
||||
}
|
||||
|
||||
// This is exception, err already checked above. Here just a print
|
||||
ast.Print(nil, err)
|
||||
s.log.Fatal("Failed to parse dir", "error", err)
|
||||
}
|
||||
// Skip "main" packages.
|
||||
delete(pkgMap, "main")
|
||||
|
||||
// Ignore packages that end with _test
|
||||
// These cannot be included in source code that is not generated specifically as a test
|
||||
for i := range pkgMap {
|
||||
if len(i) > 6 {
|
||||
if string(i[len(i)-5:]) == "_test" {
|
||||
delete(pkgMap, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no code in this directory, skip it.
|
||||
if len(pkgMap) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// There should be only one package in this directory.
|
||||
if len(pkgMap) > 1 {
|
||||
for i := range pkgMap {
|
||||
println("Found package ", i)
|
||||
}
|
||||
utils.Logger.Fatal("Most unexpected! Multiple packages in a single directory:", "packages", pkgMap)
|
||||
}
|
||||
|
||||
// At this point there is only one package in the pkgs map,
|
||||
p := &packages.Package{}
|
||||
p.PkgPath = pkgImportPath
|
||||
p.Fset = fset
|
||||
for _, pkg := range pkgMap {
|
||||
p.Name = pkg.Name
|
||||
s.log.Info("Found package","pkg.Name", pkg.Name,"p.Name", p.PkgPath)
|
||||
for filename,astFile := range pkg.Files {
|
||||
p.Syntax = append(p.Syntax,astFile)
|
||||
p.GoFiles = append(p.GoFiles,filename)
|
||||
}
|
||||
}
|
||||
s.packageList = append(s.packageList, p)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// This function is used to populate a map so that we can lookup controller embedded types in order to determine
|
||||
// if a Struct inherits from from revel.Controller
|
||||
func (s *SourceProcessor) addImportMap() (err error) {
|
||||
s.importMap = map[string]string{}
|
||||
s.packageMap = map[string]string{}
|
||||
@@ -113,41 +226,11 @@ func (s *SourceProcessor) addImportMap() (err error) {
|
||||
if len(p.Errors) > 0 {
|
||||
// Generate a compile error
|
||||
for _, e := range p.Errors {
|
||||
if !strings.Contains(e.Msg, "fsnotify") {
|
||||
err = utils.NewCompileError("", "", e)
|
||||
}
|
||||
s.log.Info("While reading packages encountered import error ignoring ", "PkgPath", p.PkgPath, "error", e)
|
||||
}
|
||||
}
|
||||
for _, tree := range p.Syntax {
|
||||
for _, decl := range tree.Decls {
|
||||
genDecl, ok := decl.(*ast.GenDecl)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if genDecl.Tok == token.IMPORT {
|
||||
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:]
|
||||
}
|
||||
}
|
||||
s.importMap[pkgAlias] = fullPath
|
||||
}
|
||||
}
|
||||
}
|
||||
s.importMap[tree.Name.Name] = p.PkgPath
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -165,53 +248,3 @@ func (s *SourceProcessor) addSourceInfo() (err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Add imports to the map from the source dir
|
||||
//func addImports(imports map[string]string, decl ast.Decl, srcDir string) {
|
||||
// genDecl, ok := decl.(*ast.GenDecl)
|
||||
// if !ok {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if genDecl.Tok != token.IMPORT {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// for _, spec := range genDecl.Specs {
|
||||
// importSpec := spec.(*ast.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 the package was not aliased (common case), we have to import it
|
||||
// // to see what the package name is.
|
||||
// // TODO: Can improve performance here a lot:
|
||||
// // 1. Do not import everything over and over again. Keep a cache.
|
||||
// // 2. Exempt the standard library; their directories always match the package name.
|
||||
// // 3. Can use build.FindOnly and then use parser.ParseDir with mode PackageClauseOnly
|
||||
// if pkgAlias == "" {
|
||||
//
|
||||
// utils.Logger.Debug("Reading from build", "path", fullPath, "srcPath", srcDir, "gopath", build.Default.GOPATH)
|
||||
// pkg, err := build.Import(fullPath, srcDir, 0)
|
||||
// if err != nil {
|
||||
// // We expect this to happen for apps using reverse routing (since we
|
||||
// // have not yet generated the routes). Don't log that.
|
||||
// if !strings.HasSuffix(fullPath, "/app/routes") {
|
||||
// utils.Logger.Warn("Could not find import:", "path", fullPath, "srcPath", srcDir, "error", err)
|
||||
// }
|
||||
// continue
|
||||
// } else {
|
||||
// utils.Logger.Debug("Found package in dir", "dir", pkg.Dir, "name", pkg.ImportPath)
|
||||
// }
|
||||
// pkgAlias = pkg.Name
|
||||
// }
|
||||
//
|
||||
// imports[pkgAlias] = fullPath
|
||||
// }
|
||||
//}
|
||||
14
revel/new.go
14
revel/new.go
@@ -72,7 +72,7 @@ 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)
|
||||
return utils.NewBuildError("Abort: Import path already exists.", "path", c.ImportPath, "apppath", c.AppPath)
|
||||
}
|
||||
|
||||
// checking and setting skeleton
|
||||
@@ -112,6 +112,10 @@ func newApp(c *model.CommandConfig) (err error) {
|
||||
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 {
|
||||
// Need to prep the run command
|
||||
c.Run.ImportPath = c.ImportPath
|
||||
updateRunConfig(c,nil)
|
||||
c.UpdateImportPath()
|
||||
runApp(c)
|
||||
} else {
|
||||
fmt.Fprintln(os.Stdout, "\nYou can run it with:\n revel run -a ", c.ImportPath)
|
||||
@@ -203,13 +207,13 @@ 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.
|
||||
// so check basic part of the path, which is "."
|
||||
if filepath.IsAbs(c.ImportPath) || strings.HasPrefix(c.ImportPath, ".") {
|
||||
utils.Logger.Fatalf("Abort: '%s' looks like a directory. Please provide a Go import path instead.",
|
||||
c.ImportPath)
|
||||
}
|
||||
|
||||
// If we are running a vendored version of Revel we do not need to check for it.
|
||||
if !c.Vendored {
|
||||
if filepath.IsAbs(c.ImportPath) || strings.HasPrefix(c.ImportPath, ".") {
|
||||
utils.Logger.Fatalf("Abort: '%s' looks like a directory. Please provide a Go import path instead.",
|
||||
c.ImportPath)
|
||||
}
|
||||
_, err = build.Import(model.RevelImportPath, "", build.FindOnly)
|
||||
if err != nil {
|
||||
//// Go get the revel project
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -34,8 +34,8 @@ func TestVersion(t *testing.T) {
|
||||
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")
|
||||
if err := os.RemoveAll(gopath); err != nil && err!=os.ErrNotExist {
|
||||
a.Fail("Failed to remove test path",err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +203,8 @@ func Walk(root string, walkFn filepath.WalkFunc) error {
|
||||
return fsWalk(root, root, walkFn)
|
||||
}
|
||||
|
||||
// Walk the tree using the function
|
||||
// Walk the path tree using the function
|
||||
// Every file found will call the function
|
||||
func fsWalk(fname string, linkName string, walkFn filepath.WalkFunc) error {
|
||||
fsWalkFunc := func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
@@ -308,9 +309,13 @@ func Exists(filename string) bool {
|
||||
// empty returns true if the given directory is empty.
|
||||
// the directory must exist.
|
||||
func Empty(dirname string) bool {
|
||||
if !DirExists(dirname) {
|
||||
return true
|
||||
}
|
||||
dir, err := os.Open(dirname)
|
||||
if err != nil {
|
||||
Logger.Infof("error opening directory: %s", err)
|
||||
return false
|
||||
}
|
||||
defer func() {
|
||||
_ = dir.Close()
|
||||
@@ -322,8 +327,8 @@ func Empty(dirname string) bool {
|
||||
// Find the full source dir for the import path, uses the build.Default.GOPATH to search for the directory
|
||||
func FindSrcPaths(appPath string, packageList []string, packageResolver func(pkgName string) error) (sourcePathsmap map[string]string, err error) {
|
||||
sourcePathsmap, missingList, err := findSrcPaths(appPath, packageList)
|
||||
if err != nil && packageResolver != nil || len(missingList)>0 {
|
||||
Logger.Info("Failed to find package, attempting to call resolver for missing packages","missing packages",missingList)
|
||||
if err != nil && packageResolver != nil || len(missingList) > 0 {
|
||||
Logger.Info("Failed to find package, attempting to call resolver for missing packages", "missing packages", missingList)
|
||||
for _, item := range missingList {
|
||||
if err = packageResolver(item); err != nil {
|
||||
return
|
||||
@@ -352,25 +357,25 @@ func findSrcPaths(appPath string, packagesList []string) (sourcePathsmap map[str
|
||||
Dir:appPath,
|
||||
}
|
||||
sourcePathsmap = map[string]string{}
|
||||
Logger.Infof("Environment path %s root %s config env %s", os.Getenv("GOPATH"), os.Getenv("GOROOT"),config.Env)
|
||||
Logger.Infof("Environment path %s root %s config env %s", os.Getenv("GOPATH"), os.Getenv("GOROOT"), config.Env)
|
||||
|
||||
pkgs, err := packages.Load(config, packagesList...)
|
||||
Logger.Infof("Environment path %s root %s config env %s", os.Getenv("GOPATH"), os.Getenv("GOROOT"),config.Env)
|
||||
Logger.Infof("Environment path %s root %s config env %s", os.Getenv("GOPATH"), os.Getenv("GOROOT"), config.Env)
|
||||
Logger.Info("Loaded packages ", "len results", len(pkgs), "error", err, "basedir", appPath)
|
||||
for _, packageName := range packagesList {
|
||||
found := false
|
||||
found := false
|
||||
log := Logger.New("seeking", packageName)
|
||||
for _, pck := range pkgs {
|
||||
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()
|
||||
log.Info("Found ", "count", len(pck.GoFiles), "App Import Path", pck.ID, "apppath", appPath)
|
||||
if len(pck.GoFiles)>0 {
|
||||
if len(pck.GoFiles) > 0 {
|
||||
sourcePathsmap[packageName] = filepath.Dir(pck.GoFiles[0])
|
||||
found = true
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ type DiscerningListener interface {
|
||||
// Watcher allows listeners to register to be notified of changes under a given
|
||||
// directory.
|
||||
type Watcher struct {
|
||||
// Parallel arrays of watcher/listener pairs.
|
||||
// Parallel arrays of watcher/listener pairs.
|
||||
watchers []*fsnotify.Watcher
|
||||
listeners []Listener
|
||||
forceRefresh bool
|
||||
@@ -42,8 +42,8 @@ type Watcher struct {
|
||||
lastError int
|
||||
notifyMutex sync.Mutex
|
||||
paths *model.RevelContainer
|
||||
refreshTimer *time.Timer // The timer to countdown the next refresh
|
||||
timerMutex *sync.Mutex // A mutex to prevent concurrent updates
|
||||
refreshTimer *time.Timer // The timer to countdown the next refresh
|
||||
timerMutex *sync.Mutex // A mutex to prevent concurrent updates
|
||||
refreshChannel chan *utils.SourceError
|
||||
refreshChannelCount int
|
||||
refreshTimerMS time.Duration // The number of milliseconds between refreshing builds
|
||||
@@ -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) &&
|
||||
@@ -85,7 +85,7 @@ func (w *Watcher) Listen(listener Listener, roots ...string) {
|
||||
for _, p := range roots {
|
||||
// is the directory / file a symlink?
|
||||
f, err := os.Lstat(p)
|
||||
if err == nil && f.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||
if err == nil && f.Mode() & os.ModeSymlink == os.ModeSymlink {
|
||||
var realPath string
|
||||
realPath, err = filepath.EvalSymlinks(p)
|
||||
if err != nil {
|
||||
@@ -200,12 +200,13 @@ func (w *Watcher) Notify() *utils.SourceError {
|
||||
case <-watcher.Errors:
|
||||
continue
|
||||
default:
|
||||
// No events left to pull
|
||||
// No events left to pull
|
||||
}
|
||||
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 {
|
||||
@@ -285,22 +286,10 @@ func (w *Watcher) rebuildRequired(ev fsnotify.Event, listener Listener) bool {
|
||||
}
|
||||
|
||||
if dl, ok := listener.(DiscerningListener); ok {
|
||||
if !dl.WatchFile(ev.Name) || ev.Op&fsnotify.Chmod == fsnotify.Chmod {
|
||||
if !dl.WatchFile(ev.Name) || ev.Op & fsnotify.Chmod == fsnotify.Chmod {
|
||||
return false
|
||||
}
|
||||
}
|
||||
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