mirror of
https://github.com/kevin-DL/revel-cmd.git
synced 2026-01-12 11:05:19 +00:00
Added Version -u to update the checked out libaraies Enhanced new skeleton toto support http https and git schemas when cloning the skeleton repo. Enhanced version command to fetch server version from master branch Enhanced version command to update local repository if a new version exists on the server
286 lines
10 KiB
Go
286 lines
10 KiB
Go
// This package will be shared between Revel and Revel CLI eventually
|
|
package model
|
|
|
|
import (
|
|
"github.com/revel/cmd/utils"
|
|
"github.com/revel/config"
|
|
"go/build"
|
|
|
|
"errors"
|
|
"fmt"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
type (
|
|
// The container object for describing all Revels variables
|
|
RevelContainer struct {
|
|
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
|
|
}
|
|
|
|
WrappedRevelCallback struct {
|
|
FireEventFunction func(key Event, value interface{}) (response EventResponse)
|
|
ImportFunction func(pkgName string) error
|
|
}
|
|
)
|
|
|
|
// Simple Wrapped RevelCallback
|
|
func NewWrappedRevelCallback(fe func(key Event, value interface{}) (response EventResponse), ie func(pkgName string) error) RevelCallback {
|
|
return &WrappedRevelCallback{fe, ie}
|
|
}
|
|
|
|
// 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"
|
|
var RevelModulesImportPath = "github.com/revel/modules"
|
|
|
|
// 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, err error) {
|
|
rp = &RevelContainer{ModulePathMap: map[string]string{}}
|
|
// Ignore trailing slashes.
|
|
rp.ImportPath = strings.TrimRight(importPath, "/")
|
|
rp.SourcePath = srcPath
|
|
rp.RunMode = mode
|
|
|
|
// 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 == "" {
|
|
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")
|
|
|
|
// Sanity check , ensure app and conf paths exist
|
|
if !utils.DirExists(rp.AppPath) {
|
|
return rp, fmt.Errorf("No application found at path %s", rp.AppPath)
|
|
}
|
|
if !utils.DirExists(filepath.Join(rp.BasePath, "conf")) {
|
|
return rp, fmt.Errorf("No configuration found at path %s", filepath.Join(rp.BasePath, "conf"))
|
|
}
|
|
|
|
rp.ViewsPath = filepath.Join(rp.AppPath, "views")
|
|
rp.CodePaths = []string{rp.AppPath}
|
|
rp.TemplatePaths = []string{}
|
|
|
|
if rp.ConfPaths == nil {
|
|
rp.ConfPaths = []string{}
|
|
}
|
|
|
|
// Config load order
|
|
// 1. framework (revel/conf/*)
|
|
// 2. application (conf/*)
|
|
// 3. user supplied configs (...) - User configs can override/add any from above
|
|
rp.ConfPaths = append(
|
|
[]string{
|
|
filepath.Join(rp.RevelPath, "conf"),
|
|
filepath.Join(rp.BasePath, "conf"),
|
|
},
|
|
rp.ConfPaths...)
|
|
|
|
rp.Config, err = config.LoadContext("app.conf", rp.ConfPaths)
|
|
if err != nil {
|
|
return rp, fmt.Errorf("Unable to load configuartion file %s", err)
|
|
}
|
|
|
|
// Ensure that the selected runmode appears in app.conf.
|
|
// If empty string is passed as the mode, treat it as "DEFAULT"
|
|
if mode == "" {
|
|
mode = config.DefaultSection
|
|
}
|
|
if !rp.Config.HasSection(mode) {
|
|
return rp, fmt.Errorf("app.conf: No mode found: %s %s", "run-mode", mode)
|
|
}
|
|
rp.Config.SetSection(mode)
|
|
|
|
// Configure properties from app.conf
|
|
rp.DevMode = rp.Config.BoolDefault("mode.dev", false)
|
|
rp.HTTPPort = rp.Config.IntDefault("http.port", 9000)
|
|
rp.HTTPAddr = rp.Config.StringDefault("http.addr", "")
|
|
rp.HTTPSsl = rp.Config.BoolDefault("http.ssl", false)
|
|
rp.HTTPSslCert = rp.Config.StringDefault("http.sslcert", "")
|
|
rp.HTTPSslKey = rp.Config.StringDefault("http.sslkey", "")
|
|
if rp.HTTPSsl {
|
|
if rp.HTTPSslCert == "" {
|
|
return rp, errors.New("No http.sslcert provided.")
|
|
}
|
|
if rp.HTTPSslKey == "" {
|
|
return rp, errors.New("No http.sslkey provided.")
|
|
}
|
|
}
|
|
//
|
|
rp.AppName = rp.Config.StringDefault("app.name", "(not set)")
|
|
rp.AppRoot = rp.Config.StringDefault("app.root", "")
|
|
rp.CookiePrefix = rp.Config.StringDefault("cookie.prefix", "REVEL")
|
|
rp.CookieDomain = rp.Config.StringDefault("cookie.domain", "")
|
|
rp.CookieSecure = rp.Config.BoolDefault("cookie.secure", rp.HTTPSsl)
|
|
rp.SecretStr = rp.Config.StringDefault("app.secret", "")
|
|
|
|
callback.FireEvent(REVEL_BEFORE_MODULES_LOADED, nil)
|
|
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() (err error) {
|
|
rp.MimeConfig, err = config.LoadContext("mime-types.conf", rp.ConfPaths)
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to load mime type config: %s %s", "error", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Loads modules based on the configuration setup.
|
|
// This will fire the REVEL_BEFORE_MODULE_LOADED, REVEL_AFTER_MODULE_LOADED
|
|
// 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) (err error) {
|
|
keys := []string{}
|
|
for _, key := range rp.Config.Options("module.") {
|
|
keys = append(keys, key)
|
|
}
|
|
|
|
// Reorder module order by key name, a poor mans sort but at least it is consistent
|
|
sort.Strings(keys)
|
|
for _, key := range keys {
|
|
moduleImportPath := rp.Config.StringDefault(key, "")
|
|
if moduleImportPath == "" {
|
|
continue
|
|
}
|
|
|
|
modulePath, err := rp.ResolveImportPath(moduleImportPath)
|
|
if err != nil {
|
|
utils.Logger.Info("Missing module ", "module_import_path", 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."):]
|
|
if index := strings.Index(name, "."); index > -1 {
|
|
name = name[index+1:]
|
|
}
|
|
callback.FireEvent(REVEL_BEFORE_MODULE_LOADED, []interface{}{rp, name, moduleImportPath, modulePath})
|
|
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
|
|
func (rp *RevelContainer) addModulePaths(name, importPath, modulePath string) {
|
|
if codePath := filepath.Join(modulePath, "app"); utils.DirExists(codePath) {
|
|
rp.CodePaths = append(rp.CodePaths, codePath)
|
|
rp.ModulePathMap[name] = modulePath
|
|
if viewsPath := filepath.Join(modulePath, "app", "views"); utils.DirExists(viewsPath) {
|
|
rp.TemplatePaths = append(rp.TemplatePaths, viewsPath)
|
|
}
|
|
}
|
|
|
|
// Hack: There is presently no way for the testrunner module to add the
|
|
// "test" subdirectory to the CodePaths. So this does it instead.
|
|
if importPath == rp.Config.StringDefault("module.testrunner", "github.com/revel/modules/testrunner") {
|
|
joinedPath := filepath.Join(rp.BasePath, "tests")
|
|
rp.CodePaths = append(rp.CodePaths, joinedPath)
|
|
}
|
|
if testsPath := filepath.Join(modulePath, "tests"); utils.DirExists(testsPath) {
|
|
rp.CodePaths = append(rp.CodePaths, testsPath)
|
|
}
|
|
}
|
|
|
|
// ResolveImportPath returns the filesystem path for the given import path.
|
|
// Returns an error if the import path could not be found.
|
|
func (rp *RevelContainer) ResolveImportPath(importPath string) (string, error) {
|
|
if rp.Packaged {
|
|
return filepath.Join(rp.SourcePath, importPath), nil
|
|
}
|
|
|
|
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
|
|
}
|