mirror of
https://github.com/kevin-DL/revel-cmd.git
synced 2026-01-11 18:54:31 +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:
@@ -2,11 +2,14 @@ package model
|
||||
|
||||
// The constants
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/revel/cmd/logger"
|
||||
"github.com/revel/cmd/utils"
|
||||
"go/build"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"github.com/revel/cmd/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -25,58 +28,58 @@ type (
|
||||
|
||||
// The Command config for the line input
|
||||
CommandConfig struct {
|
||||
Index COMMAND // The index
|
||||
Verbose bool `short:"v" long:"debug" description:"If set the logger is set to verbose"` // True if debug is active
|
||||
HistoricMode bool `long:"historic-run-mode" description:"If set the runmode is passed a string not json"` // True if debug is active
|
||||
ImportPath string // The import path (converted from various commands)
|
||||
GoPath string // The GoPath
|
||||
GoCmd string // The full path to the go executable
|
||||
SrcRoot string // The source root
|
||||
AppPath string // The application path
|
||||
AppName string // The applicaiton name
|
||||
BasePath string // The base path
|
||||
SkeletonPath string // The skeleton path
|
||||
BuildFlags []string `short:"X" long:"build-flags" description:"These flags will be used when building the application. May be specified multiple times, only applicable for Build, Run, Package, Test commands"`
|
||||
Index COMMAND // The index
|
||||
Verbose []bool `short:"v" long:"debug" description:"If set the logger is set to verbose"` // True if debug is active
|
||||
HistoricMode bool `long:"historic-run-mode" description:"If set the runmode is passed a string not json"` // True if debug is active
|
||||
ImportPath string // The import path (relative to a GOPATH)
|
||||
GoPath string // The GoPath
|
||||
GoCmd string // The full path to the go executable
|
||||
SrcRoot string // The source root
|
||||
AppPath string // The application path (absolute)
|
||||
AppName string // The application name
|
||||
PackageResolver func(pkgName string) error // a packge resolver for the config
|
||||
BuildFlags []string `short:"X" long:"build-flags" description:"These flags will be used when building the application. May be specified multiple times, only applicable for Build, Run, Package, Test commands"`
|
||||
// The new command
|
||||
New struct {
|
||||
ImportPath string `short:"a" long:"application-path" description:"Path to applicaiton folder" required:"true"`
|
||||
Skeleton string `short:"s" long:"skeleton" description:"Path to skeleton folder (Must exist on GO PATH)" required:"false"`
|
||||
Vendored bool `short:"V" long:"vendor" description:"True if project should contain a vendor folder to be initialized. Creates the vendor folder and the 'Gopkg.toml' file in the root"`
|
||||
Run bool `short:"r" long:"run" description:"True if you want to run the application right away"`
|
||||
ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"`
|
||||
SkeletonPath string `short:"s" long:"skeleton" description:"Path to skeleton folder (Must exist on GO PATH)" required:"false"`
|
||||
Vendored bool `short:"V" long:"vendor" description:"True if project should contain a vendor folder to be initialized. Creates the vendor folder and the 'Gopkg.toml' file in the root"`
|
||||
Run bool `short:"r" long:"run" description:"True if you want to run the application right away"`
|
||||
} `command:"new"`
|
||||
// The build command
|
||||
Build struct {
|
||||
TargetPath string `short:"t" long:"target-path" description:"Path to target folder. Folder will be completely deleted if it exists" required:"true"`
|
||||
ImportPath string `short:"a" long:"application-path" description:"Path to applicaiton folder" required:"true"`
|
||||
TargetPath string `short:"t" long:"target-path" description:"Path to target folder. Folder will be completely deleted if it exists" required:"false"`
|
||||
ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"`
|
||||
Mode string `short:"m" long:"run-mode" description:"The mode to run the application in"`
|
||||
CopySource bool `short:"s" long:"include-source" description:"Copy the source code as well"`
|
||||
} `command:"build"`
|
||||
// The run command
|
||||
Run struct {
|
||||
ImportPath string `short:"a" long:"application-path" description:"Path to applicaiton folder" required:"true"`
|
||||
ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"`
|
||||
Mode string `short:"m" long:"run-mode" description:"The mode to run the application in"`
|
||||
Port string `short:"p" long:"port" description:"The port to listen"`
|
||||
Port int `short:"p" long:"port" default:"-1" description:"The port to listen" `
|
||||
NoProxy bool `short:"n" long:"no-proxy" description:"True if proxy server should not be started. This will only update the main and routes files on change"`
|
||||
} `command:"run"`
|
||||
// The package command
|
||||
Package struct {
|
||||
TargetPath string `short:"t" long:"target-path" description:"Full path and filename of target package to deploy" required:"false"`
|
||||
Mode string `short:"m" long:"run-mode" description:"The mode to run the application in"`
|
||||
ImportPath string `short:"a" long:"application-path" description:"Path to applicaiton folder" required:"true"`
|
||||
ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"`
|
||||
CopySource bool `short:"s" long:"include-source" description:"Copy the source code as well"`
|
||||
} `command:"package"`
|
||||
// The clean command
|
||||
Clean struct {
|
||||
ImportPath string `short:"a" long:"application-path" description:"Path to applicaiton folder" required:"true"`
|
||||
ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"`
|
||||
} `command:"clean"`
|
||||
// The test command
|
||||
Test struct {
|
||||
Mode string `short:"m" long:"run-mode" description:"The mode to run the application in"`
|
||||
ImportPath string `short:"a" long:"application-path" description:"Path to applicaiton folder" required:"true"`
|
||||
ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"`
|
||||
Function string `short:"f" long:"suite-function" description:"The suite.function"`
|
||||
} `command:"test"`
|
||||
// The version command
|
||||
Version struct {
|
||||
ImportPath string `short:"a" long:"application-path" description:"Path to applicaiton folder" required:"false"`
|
||||
ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"`
|
||||
} `command:"version"`
|
||||
}
|
||||
)
|
||||
@@ -115,13 +118,14 @@ func (c *CommandConfig) UpdateImportPath() bool {
|
||||
currentPath, _ = filepath.Abs(importPath)
|
||||
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
for _, path := range strings.Split(build.Default.GOPATH, string(filepath.ListSeparator)) {
|
||||
utils.Logger.Infof("Checking import path %s with %s", currentPath, path)
|
||||
if strings.HasPrefix(currentPath, path) {
|
||||
importPath = currentPath[len(path) + 1:]
|
||||
if strings.HasPrefix(currentPath, path) && len(currentPath) > len(path)+1 {
|
||||
importPath = currentPath[len(path)+1:]
|
||||
// Remove the source from the path if it is there
|
||||
if len(importPath)>4 && strings.ToLower(importPath[0:4]) == "src/" {
|
||||
if len(importPath) > 4 && strings.ToLower(importPath[0:4]) == "src/" {
|
||||
importPath = importPath[4:]
|
||||
} else if importPath == "src" {
|
||||
importPath = ""
|
||||
@@ -133,6 +137,122 @@ func (c *CommandConfig) UpdateImportPath() bool {
|
||||
}
|
||||
|
||||
c.ImportPath = importPath
|
||||
utils.Logger.Info("Returned import path", "path", importPath, "buildpath",build.Default.GOPATH)
|
||||
utils.Logger.Info("Returned import path", "path", importPath, "buildpath", build.Default.GOPATH)
|
||||
return (len(importPath) > 0 || !required)
|
||||
}
|
||||
|
||||
// Used to initialize the package resolver
|
||||
func (c *CommandConfig) InitPackageResolver() {
|
||||
useVendor := utils.DirExists(filepath.Join(c.AppPath, "vendor"))
|
||||
if c.Index == NEW && c.New.Vendored {
|
||||
useVendor = true
|
||||
}
|
||||
utils.Logger.Info("InitPackageResolver", "useVendor", useVendor, "path", c.AppPath)
|
||||
|
||||
var (
|
||||
depPath string
|
||||
err error
|
||||
)
|
||||
|
||||
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.Fatal("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`")
|
||||
}
|
||||
}
|
||||
|
||||
// This should get called when needed
|
||||
c.PackageResolver = func(pkgName string) error {
|
||||
//useVendor := utils.DirExists(filepath.Join(c.AppPath, "vendor"))
|
||||
|
||||
var getCmd *exec.Cmd
|
||||
utils.Logger.Info("Request for package ", "package", pkgName, "use vendor", useVendor)
|
||||
if useVendor {
|
||||
utils.Logger.Info("Using dependency manager to import package", "package", pkgName)
|
||||
|
||||
if depPath == "" {
|
||||
utils.Logger.Error("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")
|
||||
utils.Logger.Error("Missing package", "package", pkgName)
|
||||
return fmt.Errorf("Missing package %s", pkgName)
|
||||
}
|
||||
getCmd = exec.Command(depPath, "ensure", "-add", pkgName)
|
||||
} else {
|
||||
utils.Logger.Info("No vendor folder detected, not using dependency manager to import package", "package", pkgName)
|
||||
getCmd = exec.Command(c.GoCmd, "get", pkgName)
|
||||
}
|
||||
|
||||
utils.CmdInit(getCmd, c.AppPath)
|
||||
utils.Logger.Info("Go get command ", "exec", getCmd.Path, "dir", getCmd.Dir, "args", getCmd.Args, "env", getCmd.Env, "package", pkgName)
|
||||
output, err := getCmd.CombinedOutput()
|
||||
if err != nil {
|
||||
fmt.Printf("Error stack %v\n", logger.NewCallStack())
|
||||
utils.Logger.Error("Failed to import package", "error", err, "gopath", build.Default.GOPATH, "GO-ROOT", build.Default.GOROOT, "output", string(output))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// lookup and set Go related variables
|
||||
func (c *CommandConfig) InitGoPaths() {
|
||||
// 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
|
||||
|
||||
// What we want to do is to add the import to the end of the
|
||||
// gopath, and discover which import exists - If none exist this is an error except in the case
|
||||
// where we are dealing with new which is a special case where we will attempt to target the working directory first
|
||||
workingDir, _ := os.Getwd()
|
||||
goPathList := filepath.SplitList(c.GoPath)
|
||||
bestpath := ""
|
||||
for _, path := range goPathList {
|
||||
if c.Index == NEW {
|
||||
// If the GOPATH is part of the working dir this is the most likely target
|
||||
if strings.HasPrefix(workingDir, path) {
|
||||
bestpath = path
|
||||
}
|
||||
} else {
|
||||
if utils.Exists(filepath.Join(path, "src", c.ImportPath)) {
|
||||
c.SrcRoot = path
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.SrcRoot)==0 && len(bestpath) > 0 {
|
||||
c.SrcRoot = bestpath
|
||||
}
|
||||
utils.Logger.Info("Source root", "path", c.SrcRoot, "cwd", workingDir, "gopath", c.GoPath)
|
||||
|
||||
// If source root is empty and this isn't a version then skip it
|
||||
if len(c.SrcRoot) == 0 {
|
||||
if c.Index != 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")
|
||||
|
||||
c.AppPath = filepath.Join(c.SrcRoot, filepath.FromSlash(c.ImportPath))
|
||||
utils.Logger.Info("Set application path", "path", c.AppPath)
|
||||
}
|
||||
|
||||
@@ -8,4 +8,4 @@ type EmbeddedTypeName struct {
|
||||
// Convert the type to a properly formatted import line
|
||||
func (s *EmbeddedTypeName) String() string {
|
||||
return s.ImportPath + "." + s.StructName
|
||||
}
|
||||
}
|
||||
|
||||
62
model/event.go
Normal file
62
model/event.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package model
|
||||
|
||||
type (
|
||||
// The event type
|
||||
Event int
|
||||
// The event response
|
||||
EventResponse int
|
||||
// The handler signature
|
||||
EventHandler func(typeOf Event, value interface{}) (responseOf EventResponse)
|
||||
RevelCallback interface {
|
||||
FireEvent(key Event, value interface{}) (response EventResponse)
|
||||
PackageResolver(pkgName string) error
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
// Event type when templates are going to be refreshed (receivers are registered template engines added to the template.engine conf option)
|
||||
TEMPLATE_REFRESH_REQUESTED Event = iota
|
||||
// Event type when templates are refreshed (receivers are registered template engines added to the template.engine conf option)
|
||||
TEMPLATE_REFRESH_COMPLETED
|
||||
// Event type before all module loads, events thrown to handlers added to AddInitEventHandler
|
||||
|
||||
// Event type before all module loads, events thrown to handlers added to AddInitEventHandler
|
||||
REVEL_BEFORE_MODULES_LOADED
|
||||
// Event type before module loads, events thrown to handlers added to AddInitEventHandler
|
||||
REVEL_BEFORE_MODULE_LOADED
|
||||
// Event type after module loads, events thrown to handlers added to AddInitEventHandler
|
||||
REVEL_AFTER_MODULE_LOADED
|
||||
// Event type after all module loads, events thrown to handlers added to AddInitEventHandler
|
||||
REVEL_AFTER_MODULES_LOADED
|
||||
|
||||
// Event type before server engine is initialized, receivers are active server engine and handlers added to AddInitEventHandler
|
||||
ENGINE_BEFORE_INITIALIZED
|
||||
// Event type before server engine is started, receivers are active server engine and handlers added to AddInitEventHandler
|
||||
ENGINE_STARTED
|
||||
// Event type after server engine is stopped, receivers are active server engine and handlers added to AddInitEventHandler
|
||||
ENGINE_SHUTDOWN
|
||||
|
||||
// Called before routes are refreshed
|
||||
ROUTE_REFRESH_REQUESTED
|
||||
// Called after routes have been refreshed
|
||||
ROUTE_REFRESH_COMPLETED
|
||||
|
||||
// Fired when a panic is caught during the startup process
|
||||
REVEL_FAILURE
|
||||
)
|
||||
|
||||
var initEventList = []EventHandler{} // Event handler list for receiving events
|
||||
|
||||
// Fires system events from revel
|
||||
func RaiseEvent(key Event, value interface{}) (response EventResponse) {
|
||||
for _, handler := range initEventList {
|
||||
response |= handler(key, value)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Add event handler to listen for all system events
|
||||
func AddInitEventHandler(handler EventHandler) {
|
||||
initEventList = append(initEventList, handler)
|
||||
return
|
||||
}
|
||||
24
model/event_test.go
Normal file
24
model/event_test.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package model_test
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Test that the event handler can be attached and it dispatches the event received
|
||||
func TestEventHandler(t *testing.T) {
|
||||
counter := 0
|
||||
newListener := func(typeOf revel.Event, value interface{}) (responseOf revel.EventResponse) {
|
||||
if typeOf == revel.REVEL_FAILURE {
|
||||
counter++
|
||||
}
|
||||
return
|
||||
}
|
||||
// Attach the same handlder twice so we expect to see the response twice as well
|
||||
revel.AddInitEventHandler(newListener)
|
||||
revel.AddInitEventHandler(newListener)
|
||||
revel.RaiseEvent(revel.REVEL_AFTER_MODULES_LOADED, nil)
|
||||
revel.RaiseEvent(revel.REVEL_FAILURE, nil)
|
||||
assert.Equal(t, counter, 2, "Expected event handler to have been called")
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package model
|
||||
|
||||
|
||||
// methodCall describes a call to c.Render(..)
|
||||
// It documents the argument names used, in order to propagate them to RenderArgs.
|
||||
type MethodCall struct {
|
||||
@@ -22,4 +21,3 @@ type MethodArg struct {
|
||||
TypeExpr TypeExpr // The name of the type, e.g. "int", "*pkg.UserType"
|
||||
ImportPath string // If the arg is of an imported type, this is the import path.
|
||||
}
|
||||
|
||||
|
||||
@@ -6,92 +6,96 @@ import (
|
||||
"github.com/revel/config"
|
||||
"go/build"
|
||||
|
||||
"os"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
const (
|
||||
// Event type when templates are going to be refreshed (receivers are registered template engines added to the template.engine conf option)
|
||||
TEMPLATE_REFRESH_REQUESTED = iota
|
||||
// Event type when templates are refreshed (receivers are registered template engines added to the template.engine conf option)
|
||||
TEMPLATE_REFRESH_COMPLETED
|
||||
// Event type before all module loads, events thrown to handlers added to AddInitEventHandler
|
||||
|
||||
// Event type before all module loads, events thrown to handlers added to AddInitEventHandler
|
||||
REVEL_BEFORE_MODULES_LOADED
|
||||
// Event type called when a new module is found
|
||||
REVEL_BEFORE_MODULE_LOADED
|
||||
// Event type called when after a new module is found
|
||||
REVEL_AFTER_MODULE_LOADED
|
||||
// Event type after all module loads, events thrown to handlers added to AddInitEventHandler
|
||||
REVEL_AFTER_MODULES_LOADED
|
||||
|
||||
// Event type before server engine is initialized, receivers are active server engine and handlers added to AddInitEventHandler
|
||||
ENGINE_BEFORE_INITIALIZED
|
||||
// Event type before server engine is started, receivers are active server engine and handlers added to AddInitEventHandler
|
||||
ENGINE_STARTED
|
||||
// Event type after server engine is stopped, receivers are active server engine and handlers added to AddInitEventHandler
|
||||
ENGINE_SHUTDOWN
|
||||
|
||||
// Called before routes are refreshed
|
||||
ROUTE_REFRESH_REQUESTED
|
||||
// Called after routes have been refreshed
|
||||
ROUTE_REFRESH_COMPLETED
|
||||
)
|
||||
type (
|
||||
// The container object for describing all Revels variables
|
||||
RevelContainer struct {
|
||||
ImportPath string // The import path
|
||||
SourcePath string // The full source path
|
||||
RunMode string // The current run mode
|
||||
RevelPath string // The path to the Revel source code
|
||||
BasePath string // The base path to the application
|
||||
AppPath string // The application path (BasePath + "/app"
|
||||
ViewsPath string // The application views path
|
||||
CodePaths []string // All the code paths
|
||||
TemplatePaths []string // All the template paths
|
||||
ConfPaths []string // All the configuration paths
|
||||
Config *config.Context // The global config object
|
||||
Packaged bool // True if packaged
|
||||
DevMode bool // True if running in dev mode
|
||||
HTTPPort int // The http port
|
||||
HTTPAddr string // The http address
|
||||
HTTPSsl bool // True if running https
|
||||
HTTPSslCert string // The SSL certificate
|
||||
HTTPSslKey string // The SSL key
|
||||
AppName string // The application name
|
||||
AppRoot string // The application root from the config `app.root`
|
||||
CookiePrefix string // The cookie prefix
|
||||
CookieDomain string // The cookie domain
|
||||
CookieSecure bool // True if cookie is secure
|
||||
SecretStr string // The secret string
|
||||
MimeConfig *config.Context // The mime configuration
|
||||
BuildPaths struct {
|
||||
Revel string
|
||||
}
|
||||
Paths struct {
|
||||
Import string
|
||||
Source string
|
||||
Base string
|
||||
App string
|
||||
Views string
|
||||
Code []string
|
||||
Template []string
|
||||
Config []string
|
||||
}
|
||||
PackageInfo struct {
|
||||
Config config.Context
|
||||
Packaged bool
|
||||
DevMode bool
|
||||
Vendor bool
|
||||
}
|
||||
Application struct {
|
||||
Name string
|
||||
Root string
|
||||
}
|
||||
|
||||
ImportPath string // The import path
|
||||
SourcePath string // The full source path
|
||||
RunMode string // The current run mode
|
||||
RevelPath string // The path to the Revel source code
|
||||
BasePath string // The base path to the application
|
||||
AppPath string // The application path (BasePath + "/app")
|
||||
ViewsPath string // The application views path
|
||||
CodePaths []string // All the code paths
|
||||
TemplatePaths []string // All the template paths
|
||||
ConfPaths []string // All the configuration paths
|
||||
Config *config.Context // The global config object
|
||||
Packaged bool // True if packaged
|
||||
DevMode bool // True if running in dev mode
|
||||
HTTPPort int // The http port
|
||||
HTTPAddr string // The http address
|
||||
HTTPSsl bool // True if running https
|
||||
HTTPSslCert string // The SSL certificate
|
||||
HTTPSslKey string // The SSL key
|
||||
AppName string // The application name
|
||||
AppRoot string // The application root from the config `app.root`
|
||||
CookiePrefix string // The cookie prefix
|
||||
CookieDomain string // The cookie domain
|
||||
CookieSecure bool // True if cookie is secure
|
||||
SecretStr string // The secret string
|
||||
MimeConfig *config.Context // The mime configuration
|
||||
ModulePathMap map[string]string // The module path map
|
||||
}
|
||||
|
||||
RevelCallback interface {
|
||||
FireEvent(key int, value interface{}) (response int)
|
||||
WrappedRevelCallback struct {
|
||||
FireEventFunction func(key Event, value interface{}) (response EventResponse)
|
||||
ImportFunction func(pkgName string) error
|
||||
}
|
||||
doNothingRevelCallback struct {
|
||||
|
||||
}
|
||||
|
||||
)
|
||||
|
||||
// Simple callback to pass to the RevelCallback that does nothing
|
||||
var DoNothingRevelCallback = RevelCallback(&doNothingRevelCallback{})
|
||||
// Simple Wrapped RevelCallback
|
||||
func NewWrappedRevelCallback(fe func(key Event, value interface{}) (response EventResponse), ie func(pkgName string) error) RevelCallback {
|
||||
return &WrappedRevelCallback{fe, ie}
|
||||
}
|
||||
|
||||
func (_ *doNothingRevelCallback) FireEvent(key int, value interface{}) (response int) {
|
||||
// Function to implement the FireEvent
|
||||
func (w *WrappedRevelCallback) FireEvent(key Event, value interface{}) (response EventResponse) {
|
||||
if w.FireEventFunction != nil {
|
||||
response = w.FireEventFunction(key, value)
|
||||
}
|
||||
return
|
||||
}
|
||||
func (w *WrappedRevelCallback) PackageResolver(pkgName string) error {
|
||||
return w.ImportFunction(pkgName)
|
||||
}
|
||||
|
||||
// RevelImportPath Revel framework import path
|
||||
var RevelImportPath = "github.com/revel/revel"
|
||||
|
||||
// This function returns a container object describing the revel application
|
||||
// eventually this type of function will replace the global variables.
|
||||
func NewRevelPaths(mode, importPath, srcPath string, callback RevelCallback) (rp *RevelContainer) {
|
||||
func NewRevelPaths(mode, importPath, srcPath string, callback RevelCallback) (rp *RevelContainer, err error) {
|
||||
rp = &RevelContainer{ModulePathMap: map[string]string{}}
|
||||
// Ignore trailing slashes.
|
||||
rp.ImportPath = strings.TrimRight(importPath, "/")
|
||||
@@ -101,17 +105,20 @@ func NewRevelPaths(mode, importPath, srcPath string, callback RevelCallback) (rp
|
||||
// If the SourcePath is not specified, find it using build.Import.
|
||||
var revelSourcePath string // may be different from the app source path
|
||||
if rp.SourcePath == "" {
|
||||
revelSourcePath, rp.SourcePath = findSrcPaths(importPath)
|
||||
rp.SourcePath, revelSourcePath, err = utils.FindSrcPaths(importPath, RevelImportPath, callback.PackageResolver)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// If the SourcePath was specified, assume both Revel and the app are within it.
|
||||
rp.SourcePath = filepath.Clean(rp.SourcePath)
|
||||
revelSourcePath = rp.SourcePath
|
||||
|
||||
}
|
||||
|
||||
// Setup paths for application
|
||||
rp.RevelPath = filepath.Join(revelSourcePath, filepath.FromSlash(RevelImportPath))
|
||||
rp.BasePath = filepath.Join(rp.SourcePath, filepath.FromSlash(importPath))
|
||||
rp.PackageInfo.Vendor = utils.Exists(filepath.Join(rp.BasePath, "vendor"))
|
||||
rp.AppPath = filepath.Join(rp.BasePath, "app")
|
||||
rp.ViewsPath = filepath.Join(rp.AppPath, "views")
|
||||
|
||||
@@ -133,11 +140,9 @@ func NewRevelPaths(mode, importPath, srcPath string, callback RevelCallback) (rp
|
||||
},
|
||||
rp.ConfPaths...)
|
||||
|
||||
var err error
|
||||
rp.Config, err = config.LoadContext("app.conf", rp.ConfPaths)
|
||||
if err != nil {
|
||||
utils.Logger.Fatal("Unable to load configuartion file ","error", err)
|
||||
os.Exit(1)
|
||||
return rp, fmt.Errorf("Unable to load configuartion file %s", err)
|
||||
}
|
||||
|
||||
// Ensure that the selected runmode appears in app.conf.
|
||||
@@ -146,7 +151,7 @@ func NewRevelPaths(mode, importPath, srcPath string, callback RevelCallback) (rp
|
||||
mode = config.DefaultSection
|
||||
}
|
||||
if !rp.Config.HasSection(mode) {
|
||||
utils.Logger.Fatal("app.conf: No mode found:","run-mode", mode)
|
||||
return rp, fmt.Errorf("app.conf: No mode found: %s %s", "run-mode", mode)
|
||||
}
|
||||
rp.Config.SetSection(mode)
|
||||
|
||||
@@ -159,10 +164,10 @@ func NewRevelPaths(mode, importPath, srcPath string, callback RevelCallback) (rp
|
||||
rp.HTTPSslKey = rp.Config.StringDefault("http.sslkey", "")
|
||||
if rp.HTTPSsl {
|
||||
if rp.HTTPSslCert == "" {
|
||||
utils.Logger.Fatal("No http.sslcert provided.")
|
||||
return rp, errors.New("No http.sslcert provided.")
|
||||
}
|
||||
if rp.HTTPSslKey == "" {
|
||||
utils.Logger.Fatal("No http.sslkey provided.")
|
||||
return rp, errors.New("No http.sslkey provided.")
|
||||
}
|
||||
}
|
||||
//
|
||||
@@ -173,21 +178,23 @@ func NewRevelPaths(mode, importPath, srcPath string, callback RevelCallback) (rp
|
||||
rp.CookieSecure = rp.Config.BoolDefault("cookie.secure", rp.HTTPSsl)
|
||||
rp.SecretStr = rp.Config.StringDefault("app.secret", "")
|
||||
|
||||
|
||||
callback.FireEvent(REVEL_BEFORE_MODULES_LOADED, nil)
|
||||
rp.loadModules(callback)
|
||||
if err := rp.loadModules(callback); err != nil {
|
||||
return rp, err
|
||||
}
|
||||
|
||||
callback.FireEvent(REVEL_AFTER_MODULES_LOADED, nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// LoadMimeConfig load mime-types.conf on init.
|
||||
func (rp *RevelContainer) LoadMimeConfig() {
|
||||
var err error
|
||||
func (rp *RevelContainer) LoadMimeConfig() (err error) {
|
||||
rp.MimeConfig, err = config.LoadContext("mime-types.conf", rp.ConfPaths)
|
||||
if err != nil {
|
||||
utils.Logger.Fatal("Failed to load mime type config:", "error", err)
|
||||
return fmt.Errorf("Failed to load mime type config: %s %s", "error", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Loads modules based on the configuration setup.
|
||||
@@ -195,7 +202,7 @@ func (rp *RevelContainer) LoadMimeConfig() {
|
||||
// for each module loaded. The callback will receive the RevelContainer, name, moduleImportPath and modulePath
|
||||
// It will automatically add in the code paths for the module to the
|
||||
// container object
|
||||
func (rp *RevelContainer) loadModules(callback RevelCallback) {
|
||||
func (rp *RevelContainer) loadModules(callback RevelCallback) (err error) {
|
||||
keys := []string{}
|
||||
for _, key := range rp.Config.Options("module.") {
|
||||
keys = append(keys, key)
|
||||
@@ -211,7 +218,12 @@ func (rp *RevelContainer) loadModules(callback RevelCallback) {
|
||||
|
||||
modulePath, err := rp.ResolveImportPath(moduleImportPath)
|
||||
if err != nil {
|
||||
utils.Logger.Error("Failed to load module. Import of path failed", "modulePath", moduleImportPath, "error", err)
|
||||
utils.Logger.Info("Missing module ", "module", moduleImportPath, "error",err)
|
||||
callback.PackageResolver(moduleImportPath)
|
||||
modulePath, err = rp.ResolveImportPath(moduleImportPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to load module. Import of path failed %s:%s %s:%s ", "modulePath", moduleImportPath, "error", err)
|
||||
}
|
||||
}
|
||||
// Drop anything between module.???.<name of module>
|
||||
name := key[len("module."):]
|
||||
@@ -222,6 +234,7 @@ func (rp *RevelContainer) loadModules(callback RevelCallback) {
|
||||
rp.addModulePaths(name, moduleImportPath, modulePath)
|
||||
callback.FireEvent(REVEL_AFTER_MODULE_LOADED, []interface{}{rp, name, moduleImportPath, modulePath})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Adds a module paths to the container object
|
||||
@@ -252,43 +265,12 @@ func (rp *RevelContainer) ResolveImportPath(importPath string) (string, error) {
|
||||
return filepath.Join(rp.SourcePath, importPath), nil
|
||||
}
|
||||
|
||||
modPkg, err := build.Import(importPath, rp.RevelPath, build.FindOnly)
|
||||
modPkg, err := build.Import(importPath, rp.AppPath, build.FindOnly)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if rp.PackageInfo.Vendor && !strings.HasPrefix(modPkg.Dir,rp.BasePath) {
|
||||
return "", fmt.Errorf("Module %s was found outside of path %s.",importPath, modPkg.Dir)
|
||||
}
|
||||
return modPkg.Dir, nil
|
||||
}
|
||||
|
||||
// Find the full source dir for the import path, uses the build.Default.GOPATH to search for the directory
|
||||
func findSrcPaths(importPath string) (revelSourcePath, appSourcePath string) {
|
||||
var (
|
||||
gopaths = filepath.SplitList(build.Default.GOPATH)
|
||||
goroot = build.Default.GOROOT
|
||||
)
|
||||
|
||||
if len(gopaths) == 0 {
|
||||
utils.Logger.Fatalf("GOPATH environment variable is not set. " +
|
||||
"Please refer to http://golang.org/doc/code.html to configure your Go environment.")
|
||||
}
|
||||
|
||||
if utils.ContainsString(gopaths, goroot) {
|
||||
utils.Logger.Fatalf("GOPATH (%s) must not include your GOROOT (%s). "+
|
||||
"Please refer to http://golang.org/doc/code.html to configure your Go environment.",
|
||||
gopaths, goroot)
|
||||
|
||||
}
|
||||
|
||||
appPkg, err := build.Import(importPath, "", build.FindOnly)
|
||||
if err != nil {
|
||||
utils.Logger.Fatal("Failed to import "+importPath+" with error:", "error", err)
|
||||
}
|
||||
|
||||
revelPkg, err := build.Import(RevelImportPath, appPkg.Dir, build.FindOnly)
|
||||
if err != nil {
|
||||
utils.Logger.Fatal("Failed to find Revel with error:", "error", err)
|
||||
}
|
||||
|
||||
revelSourcePath, appSourcePath = revelPkg.Dir[:len(revelPkg.Dir)-len(RevelImportPath)], appPkg.SrcRoot
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@ package model
|
||||
|
||||
// TypeInfo summarizes information about a struct type in the app source code.
|
||||
type TypeInfo struct {
|
||||
StructName string // e.g. "Application"
|
||||
ImportPath string // e.g. "github.com/revel/examples/chat/app/controllers"
|
||||
PackageName string // e.g. "controllers"
|
||||
MethodSpecs []*MethodSpec // Method specifications, the action functions
|
||||
StructName string // e.g. "Application"
|
||||
ImportPath string // e.g. "github.com/revel/examples/chat/app/controllers"
|
||||
PackageName string // e.g. "controllers"
|
||||
MethodSpecs []*MethodSpec // Method specifications, the action functions
|
||||
EmbeddedTypes []*EmbeddedTypeName // Used internally to identify controllers that indirectly embed *revel.Controller.
|
||||
}
|
||||
|
||||
@@ -13,4 +13,3 @@ type TypeInfo struct {
|
||||
func (s *TypeInfo) String() string {
|
||||
return s.ImportPath + "." + s.StructName
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user