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