mirror of
https://github.com/kevin-DL/revel-cmd.git
synced 2026-01-11 18:54:31 +00:00
Split main file
Added code to split the generated main file into two separate files. This allows other code to launch the web application inline.
This commit is contained in:
@@ -36,7 +36,7 @@ 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, buildFlags ...string) (app *App, compileError *utils.Error) {
|
||||
func Build(c *model.CommandConfig, paths *model.RevelContainer) (app *App, compileError *utils.Error) {
|
||||
// First, clear the generated files (to avoid them messing with ProcessSource).
|
||||
cleanSource(paths, "tmp", "routes")
|
||||
|
||||
@@ -56,12 +56,20 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer, buildFlags ...st
|
||||
|
||||
// Generate two source files.
|
||||
templateArgs := map[string]interface{}{
|
||||
"ImportPath": paths.ImportPath,
|
||||
"Controllers": controllers,
|
||||
"ValidationKeys": sourceInfo.ValidationKeys,
|
||||
"ImportPaths": calcImportAliases(sourceInfo),
|
||||
"TestSuites": sourceInfo.TestSuites(),
|
||||
}
|
||||
|
||||
// Generate code for the main, run and routes file.
|
||||
// The run file allows external programs to launch and run the application
|
||||
// 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)
|
||||
|
||||
// Read build config.
|
||||
@@ -126,14 +134,14 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer, buildFlags ...st
|
||||
}
|
||||
|
||||
gotten := make(map[string]struct{})
|
||||
contains := func (s []string, e string) bool {
|
||||
for _, a := range s {
|
||||
if a == e {
|
||||
return true
|
||||
}
|
||||
contains := func(s []string, e string) bool {
|
||||
for _, a := range s {
|
||||
if a == e {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
for {
|
||||
appVersion := getAppVersion(paths)
|
||||
@@ -144,7 +152,7 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer, buildFlags ...st
|
||||
|
||||
// Append any build flags specified, they will override existing flags
|
||||
flags := []string{}
|
||||
if len(c.BuildFlags)==0 {
|
||||
if len(c.BuildFlags) == 0 {
|
||||
flags = []string{
|
||||
"build",
|
||||
"-i",
|
||||
@@ -152,24 +160,23 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer, buildFlags ...st
|
||||
"-tags", buildTags,
|
||||
"-o", binName}
|
||||
} else {
|
||||
if !contains(c.BuildFlags,"build") {
|
||||
if !contains(c.BuildFlags, "build") {
|
||||
flags = []string{"build"}
|
||||
}
|
||||
flags = append(flags,c.BuildFlags...)
|
||||
flags = append(flags, c.BuildFlags...)
|
||||
if !contains(flags, "-ldflags") {
|
||||
flags = append(flags,"-ldflags", versionLinkerFlags)
|
||||
flags = append(flags, "-ldflags", versionLinkerFlags)
|
||||
}
|
||||
if !contains(flags, "-tags") {
|
||||
flags = append(flags,"-tags", buildTags)
|
||||
flags = append(flags, "-tags", buildTags)
|
||||
}
|
||||
if !contains(flags, "-o") {
|
||||
flags = append(flags,"-o", binName)
|
||||
flags = append(flags, "-o", binName)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add in build flags
|
||||
flags = append(flags, buildFlags...)
|
||||
flags = append(flags, c.BuildFlags...)
|
||||
|
||||
// This is Go main path
|
||||
gopath := c.GoPath
|
||||
@@ -236,7 +243,7 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer, buildFlags ...st
|
||||
getOutput, err := getCmd.CombinedOutput()
|
||||
if err != nil {
|
||||
utils.Logger.Error("Build failed", "message", stOutput)
|
||||
utils.Logger.Error("Failed to fetch the output", string(getOutput))
|
||||
utils.Logger.Error("Failed to fetch the output", "getOutput", string(getOutput))
|
||||
return nil, newCompileError(paths, output)
|
||||
}
|
||||
}
|
||||
@@ -329,7 +336,6 @@ 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{}) {
|
||||
cleanSource(paths, dir)
|
||||
|
||||
err := utils.MustGenerateTemplate(filepath.Join(paths.AppPath, dir, filename), templateSource, args)
|
||||
if err != nil {
|
||||
@@ -469,14 +475,13 @@ func newCompileError(paths *model.RevelContainer, output []byte) *utils.Error {
|
||||
}
|
||||
|
||||
// RevelMainTemplate template for app/tmp/main.go
|
||||
const RevelMainTemplate = `// GENERATED CODE - DO NOT EDIT
|
||||
// This file is the main file for Revel.
|
||||
const RevelRunTemplate = `// GENERATED CODE - DO NOT EDIT
|
||||
// This file is the run file for Revel.
|
||||
// It registers all the controllers and provides details for the Revel server engine to
|
||||
// properly inject parameters directly into the action endpoints.
|
||||
package main
|
||||
package run
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"reflect"
|
||||
"github.com/revel/revel"{{range $k, $v := $.ImportPaths}}
|
||||
{{$v}} "{{$k}}"{{end}}
|
||||
@@ -484,18 +489,18 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
runMode *string = flag.String("runMode", "", "Run mode.")
|
||||
port *int = flag.Int("port", 0, "By default, read from app.conf")
|
||||
importPath *string = flag.String("importPath", "", "Go Import Path for the app.")
|
||||
srcPath *string = flag.String("srcPath", "", "Path to the source root.")
|
||||
|
||||
// So compiler won't complain if the generated code doesn't reference reflect package...
|
||||
_ = reflect.Invalid
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
revel.Init(*runMode, *importPath, *srcPath)
|
||||
// Register and run the application
|
||||
func Run(port int) {
|
||||
Register()
|
||||
revel.Run(port)
|
||||
}
|
||||
|
||||
// Register all the controllers
|
||||
func Register() {
|
||||
revel.AppLog.Info("Running revel server")
|
||||
{{range $i, $c := .Controllers}}
|
||||
revel.RegisterController((*{{index $.ImportPaths .ImportPath}}.{{.StructName}})(nil),
|
||||
@@ -522,8 +527,32 @@ func main() {
|
||||
testing.TestSuites = []interface{}{ {{range .TestSuites}}
|
||||
(*{{index $.ImportPaths .ImportPath}}.{{.StructName}})(nil),{{end}}
|
||||
}
|
||||
}
|
||||
`
|
||||
const RevelMainTemplate = `// GENERATED CODE - DO NOT EDIT
|
||||
// This file is the main file for Revel.
|
||||
// It registers all the controllers and provides details for the Revel server engine to
|
||||
// properly inject parameters directly into the action endpoints.
|
||||
package main
|
||||
|
||||
revel.Run(*port)
|
||||
import (
|
||||
"flag"
|
||||
"{{.ImportPath}}/app/tmp/run"
|
||||
"github.com/revel/revel"
|
||||
)
|
||||
|
||||
var (
|
||||
runMode *string = flag.String("runMode", "", "Run mode.")
|
||||
port *int = flag.Int("port", 0, "By default, read from app.conf")
|
||||
importPath *string = flag.String("importPath", "", "Go Import Path for the app.")
|
||||
srcPath *string = flag.String("srcPath", "", "Path to the source root.")
|
||||
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
revel.Init(*runMode, *importPath, *srcPath)
|
||||
run.Run(*port)
|
||||
}
|
||||
`
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ package model
|
||||
import (
|
||||
"github.com/revel/cmd/utils"
|
||||
"path/filepath"
|
||||
"unicode"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type SourceInfo struct {
|
||||
@@ -41,9 +41,9 @@ func (s *SourceInfo) TypesThatEmbed(targetType, packageFilter string) (filtered
|
||||
processed []string
|
||||
)
|
||||
for len(nodeQueue) > 0 {
|
||||
controllerSimpleName := nodeQueue[0]
|
||||
typeSimpleName := nodeQueue[0]
|
||||
nodeQueue = nodeQueue[1:]
|
||||
processed = append(processed, controllerSimpleName)
|
||||
processed = append(processed, typeSimpleName)
|
||||
|
||||
// Look through all known structs.
|
||||
for _, spec := range s.StructSpecs {
|
||||
@@ -58,7 +58,7 @@ func (s *SourceInfo) TypesThatEmbed(targetType, packageFilter string) (filtered
|
||||
|
||||
// If so, add this type's simple name to the nodeQueue, and its spec to
|
||||
// the filtered list.
|
||||
if controllerSimpleName == embeddedType.String() {
|
||||
if typeSimpleName == embeddedType.String() {
|
||||
nodeQueue = append(nodeQueue, spec.String())
|
||||
filtered = append(filtered, spec)
|
||||
break
|
||||
@@ -66,6 +66,7 @@ func (s *SourceInfo) TypesThatEmbed(targetType, packageFilter string) (filtered
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Strip out any specifications that contain a lower case
|
||||
for exit := false; !exit; exit = true {
|
||||
for i, filteredItem := range filtered {
|
||||
@@ -84,25 +85,28 @@ func (s *SourceInfo) TypesThatEmbed(targetType, packageFilter string) (filtered
|
||||
for _, spec := range s.StructSpecs {
|
||||
if spec.PackageName == packageFilter {
|
||||
found := false
|
||||
unfoundNames := ""
|
||||
for _, filteredItem := range filtered {
|
||||
if filteredItem.StructName == spec.StructName {
|
||||
found = true
|
||||
break
|
||||
} else {
|
||||
unfoundNames += filteredItem.StructName + ","
|
||||
}
|
||||
}
|
||||
|
||||
// Report non controller structures in controller folder.
|
||||
if !found && !strings.HasPrefix(spec.StructName, "Test") {
|
||||
utils.Logger.Warn("Type found in package: " + packageFilter +
|
||||
", but did not embed from: " + filepath.Base(targetType),
|
||||
"name", spec.StructName, "path", spec.ImportPath)
|
||||
utils.Logger.Warn("Type found in package: "+packageFilter+
|
||||
", but did not embed from: "+filepath.Base(targetType),
|
||||
"name", spec.StructName, "importpath", spec.ImportPath, "foundstructures", unfoundNames)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ControllerSpecs returns the all the contollers that embeds
|
||||
// ControllerSpecs returns the all the controllers that embeds
|
||||
// `revel.Controller`
|
||||
func (s *SourceInfo) ControllerSpecs() []*TypeInfo {
|
||||
if s.controllerSpecs == nil {
|
||||
|
||||
@@ -94,12 +94,8 @@ func ProcessSource(paths *model.RevelContainer) (*model.SourceInfo, *utils.Error
|
||||
// Skip "main" packages.
|
||||
delete(pkgs, "main")
|
||||
|
||||
// If there is no code in this directory, skip it.
|
||||
if len(pkgs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Ignore packages that end with _test
|
||||
// These cannot be included in source code that is not generated specifically as a test
|
||||
for i := range pkgs {
|
||||
if len(i) > 6 {
|
||||
if string(i[len(i)-5:]) == "_test" {
|
||||
@@ -108,6 +104,11 @@ func ProcessSource(paths *model.RevelContainer) (*model.SourceInfo, *utils.Error
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no code in this directory, skip it.
|
||||
if len(pkgs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// There should be only one package in this directory.
|
||||
if len(pkgs) > 1 {
|
||||
for i := range pkgs {
|
||||
@@ -116,12 +117,17 @@ func ProcessSource(paths *model.RevelContainer) (*model.SourceInfo, *utils.Error
|
||||
utils.Logger.Fatal("Most unexpected! Multiple packages in a single directory:", "packages", pkgs)
|
||||
}
|
||||
|
||||
|
||||
var pkg *ast.Package
|
||||
for _, v := range pkgs {
|
||||
pkg = v
|
||||
}
|
||||
|
||||
srcInfo = appendSourceInfo(srcInfo, processPackage(fset, pkgImportPath, path, pkg))
|
||||
if pkg != nil {
|
||||
srcInfo = appendSourceInfo(srcInfo, processPackage(fset, pkgImportPath, path, pkg))
|
||||
} else {
|
||||
utils.Logger.Info("Ignoring package, because it contained no packages", "path", path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -109,6 +109,7 @@ func runApp(c *model.CommandConfig) {
|
||||
if c.Run.Mode == "" {
|
||||
c.Run.Mode = "dev"
|
||||
}
|
||||
c.ImportPath = c.Run.ImportPath
|
||||
|
||||
revel_path := model.NewRevelPaths(c.Run.Mode, c.Run.ImportPath, "", model.DoNothingRevelCallback)
|
||||
if c.Run.Port != "" {
|
||||
|
||||
@@ -78,6 +78,7 @@ func testApp(c *model.CommandConfig) {
|
||||
if c.Test.Mode != "" {
|
||||
mode = c.Test.Mode
|
||||
}
|
||||
c.ImportPath = c.Test.ImportPath
|
||||
|
||||
// Find and parse app.conf
|
||||
revel_path := model.NewRevelPaths(mode, c.Test.ImportPath, "", model.DoNothingRevelCallback)
|
||||
|
||||
@@ -71,7 +71,7 @@ func MustGenerateTemplate(filename, templateSource string, args map[string]inter
|
||||
sourceCode := b.String()
|
||||
filePath := filepath.Dir(filename)
|
||||
if !DirExists(filePath) {
|
||||
err = os.Mkdir(filePath, 0777)
|
||||
err = os.MkdirAll(filePath, 0777)
|
||||
if err != nil && !os.IsExist(err) {
|
||||
Logger.Fatal("Failed to make directory","dir", filePath, "error", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user