mirror of
https://github.com/kevin-DL/revel-cmd.git
synced 2026-01-11 18:54:31 +00:00
Initial rewrite of revel/cmd to provide vendor support and enhanced CLI options
This commit is contained in:
300
revel/revel.go
Normal file
300
revel/revel.go
Normal file
@@ -0,0 +1,300 @@
|
||||
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
|
||||
// Revel Framework source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// The command line tool for running Revel apps.
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/jessevdk/go-flags"
|
||||
|
||||
"github.com/agtorre/gocolorize"
|
||||
"github.com/revel/cmd/model"
|
||||
"github.com/revel/cmd/utils"
|
||||
"github.com/revel/cmd/logger"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"go/build"
|
||||
)
|
||||
|
||||
const (
|
||||
// RevelCmdImportPath Revel framework cmd tool import path
|
||||
RevelCmdImportPath = "github.com/revel/cmd"
|
||||
|
||||
// DefaultRunMode for revel's application
|
||||
DefaultRunMode = "dev"
|
||||
)
|
||||
|
||||
// Command structure cribbed from the genius organization of the "go" command.
|
||||
type Command struct {
|
||||
UpdateConfig func(c *model.CommandConfig, args []string) bool
|
||||
RunWith func(c *model.CommandConfig)
|
||||
UsageLine, Short, Long string
|
||||
}
|
||||
|
||||
// Name returns command name from usage line
|
||||
func (cmd *Command) Name() string {
|
||||
name := cmd.UsageLine
|
||||
i := strings.Index(name, " ")
|
||||
if i >= 0 {
|
||||
name = name[:i]
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// The constants
|
||||
const (
|
||||
NEW model.COMMAND = iota +1
|
||||
RUN
|
||||
BUILD
|
||||
PACAKAGE
|
||||
CLEAN
|
||||
TEST
|
||||
VERSION
|
||||
)
|
||||
// The commands
|
||||
var commands = []*Command{
|
||||
nil, // Safety net, prevent missing index from running
|
||||
cmdNew,
|
||||
cmdRun,
|
||||
cmdBuild,
|
||||
cmdPackage,
|
||||
cmdClean,
|
||||
cmdTest,
|
||||
cmdVersion,
|
||||
}
|
||||
func main() {
|
||||
if runtime.GOOS == "windows" {
|
||||
gocolorize.SetPlain(true)
|
||||
}
|
||||
c := &model.CommandConfig{}
|
||||
wd,_ := os.Getwd()
|
||||
|
||||
utils.InitLogger(wd,logger.LvlError)
|
||||
|
||||
parser := flags.NewParser(c, flags.HelpFlag | flags.PassDoubleDash)
|
||||
if ini:=flag.String("ini","none","");*ini!="none" {
|
||||
if err:=flags.NewIniParser(parser).ParseFile(*ini);err!=nil {
|
||||
utils.Logger.Error("Unable to load ini", "error",err)
|
||||
}
|
||||
} else {
|
||||
if _, err := parser.Parse(); err != nil {
|
||||
utils.Logger.Info("Command line options failed", "error", err.Error())
|
||||
|
||||
// Decode nature of error
|
||||
if perr,ok:=err.(*flags.Error); ok {
|
||||
if perr.Type == flags.ErrRequired {
|
||||
// Try the old way
|
||||
if !main_parse_old(c) {
|
||||
println("Command line error:", err.Error())
|
||||
parser.WriteHelp(os.Stdout)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
println("Command line error:", err.Error())
|
||||
parser.WriteHelp(os.Stdout)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
println("Command line error:", err.Error())
|
||||
parser.WriteHelp(os.Stdout)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
switch parser.Active.Name {
|
||||
case "new":
|
||||
c.Index = NEW
|
||||
case "run":
|
||||
c.Index = RUN
|
||||
case "build":
|
||||
c.Index = BUILD
|
||||
case "package":
|
||||
c.Index = PACAKAGE
|
||||
case "clean":
|
||||
c.Index = CLEAN
|
||||
case "test":
|
||||
c.Index = TEST
|
||||
case "version":
|
||||
c.Index = VERSION
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Switch based on the verbose flag
|
||||
if c.Verbose {
|
||||
utils.InitLogger(wd, logger.LvlDebug)
|
||||
} else {
|
||||
utils.InitLogger(wd, logger.LvlWarn)
|
||||
}
|
||||
println("Revel executing:", commands[c.Index].Short)
|
||||
// checking and setting go paths
|
||||
initGoPaths(c)
|
||||
|
||||
commands[c.Index].RunWith(c)
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Try to populate the CommandConfig using the old techniques
|
||||
func main_parse_old(c *model.CommandConfig) bool {
|
||||
// Take the old command format and try to parse them
|
||||
flag.Usage = func() { usage(1) }
|
||||
flag.Parse()
|
||||
args := flag.Args()
|
||||
|
||||
if len(args) < 1 || args[0] == "help" {
|
||||
if len(args) == 1 {
|
||||
usage(0)
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
for _, cmd := range commands {
|
||||
if cmd!=nil && cmd.Name() == args[1] {
|
||||
tmpl(os.Stdout, helpTemplate, cmd)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
usage(2)
|
||||
}
|
||||
|
||||
for _, cmd := range commands {
|
||||
if cmd!=nil && cmd.Name() == args[0] {
|
||||
println("Running", cmd.Name())
|
||||
return cmd.UpdateConfig(c, args[1:])
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func main_old() {
|
||||
if runtime.GOOS == "windows" {
|
||||
gocolorize.SetPlain(true)
|
||||
}
|
||||
fmt.Fprintf(os.Stdout, gocolorize.NewColor("blue").Paint(header))
|
||||
flag.Usage = func() { usage(1) }
|
||||
flag.Parse()
|
||||
args := flag.Args()
|
||||
|
||||
if len(args) < 1 || args[0] == "help" {
|
||||
if len(args) == 1 {
|
||||
usage(0)
|
||||
}
|
||||
if len(args) > 1 {
|
||||
for _, cmd := range commands {
|
||||
if cmd.Name() == args[1] {
|
||||
tmpl(os.Stdout, helpTemplate, cmd)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
usage(2)
|
||||
}
|
||||
|
||||
// Commands use panic to abort execution when something goes wrong.
|
||||
// Panics are logged at the point of error. Ignore those.
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
if _, ok := err.(utils.LoggedError); !ok {
|
||||
// This panic was not expected / logged.
|
||||
panic(err)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
|
||||
//for _, cmd := range commands {
|
||||
// if cmd.Name() == args[0] {
|
||||
// cmd.UpdateConfig(args[1:])
|
||||
// return
|
||||
// }
|
||||
//}
|
||||
|
||||
utils.Logger.Fatalf("unknown command %q\nRun 'revel help' for usage.\n", args[0])
|
||||
}
|
||||
|
||||
const header = `~
|
||||
~ revel! http://revel.github.io
|
||||
~
|
||||
`
|
||||
|
||||
const usageTemplate = `usage: revel command [arguments]
|
||||
|
||||
The commands are:
|
||||
{{range .}}
|
||||
{{.Name | printf "%-11s"}} {{.Short}}{{end}}
|
||||
|
||||
Use "revel help [command]" for more information.
|
||||
`
|
||||
|
||||
var helpTemplate = `usage: revel {{.UsageLine}}
|
||||
{{.Long}}
|
||||
`
|
||||
|
||||
func usage(exitCode int) {
|
||||
tmpl(os.Stderr, usageTemplate, commands)
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
|
||||
func tmpl(w io.Writer, text string, data interface{}) {
|
||||
t := template.New("top")
|
||||
template.Must(t.Parse(text))
|
||||
if err := t.Execute(w, data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
// lookup and set Go related variables
|
||||
func initGoPaths(c *model.CommandConfig) {
|
||||
// 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
|
||||
workingDir, _ := os.Getwd()
|
||||
goPathList := filepath.SplitList(c.GoPath)
|
||||
for _, path := range goPathList {
|
||||
if strings.HasPrefix(strings.ToLower(workingDir), strings.ToLower(path)) {
|
||||
c.SrcRoot = path
|
||||
break
|
||||
}
|
||||
|
||||
path, _ = filepath.EvalSymlinks(path)
|
||||
if len(path) > 0 && strings.HasPrefix(strings.ToLower(workingDir), strings.ToLower(path)) {
|
||||
c.SrcRoot = path
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.SrcRoot) == 0 {
|
||||
utils.Logger.Fatal("Abort: could not create a Revel application outside of GOPATH.")
|
||||
}
|
||||
|
||||
// set go src path
|
||||
c.SrcRoot = filepath.Join(c.SrcRoot, "src")
|
||||
}
|
||||
Reference in New Issue
Block a user