mirror of
https://gitee.com/johng/gf
synced 2026-06-07 02:12:11 +08:00
improve package gcmd/ghttp
This commit is contained in:
@ -32,20 +32,24 @@ func niceCallFunc(f func()) {
|
||||
if v, ok := exception.(error); ok && gerror.HasStack(v) {
|
||||
// It's already an error that has stack info.
|
||||
panic(v)
|
||||
} else {
|
||||
// Create a new error with stack info.
|
||||
// Note that there's a skip pointing the start stacktrace
|
||||
// of the real error point.
|
||||
if v, ok := exception.(error); ok {
|
||||
if gerror.Code(v) != gcode.CodeNil {
|
||||
panic(v)
|
||||
} else {
|
||||
panic(gerror.WrapCodeSkip(gcode.CodeInternalError, 1, v, ""))
|
||||
}
|
||||
} else {
|
||||
panic(gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception))
|
||||
}
|
||||
}
|
||||
// Create a new error with stack info.
|
||||
// Note that there's a skip pointing the start stacktrace
|
||||
// of the real error point.
|
||||
if v, ok := exception.(error); ok {
|
||||
if gerror.Code(v) != gcode.CodeNil {
|
||||
panic(v)
|
||||
} else {
|
||||
panic(gerror.WrapCodeSkip(
|
||||
gcode.CodeInternalError, 1, v, "exception recovered",
|
||||
))
|
||||
}
|
||||
} else {
|
||||
panic(gerror.NewCodeSkipf(
|
||||
gcode.CodeInternalError, 1, "exception recovered: %+v", exception,
|
||||
))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
@ -53,7 +53,7 @@ type Request struct {
|
||||
formMap map[string]interface{} // Form parameters map, which is nil if there's no form data from client.
|
||||
bodyMap map[string]interface{} // Body parameters map, which might be nil if there're no body content.
|
||||
error error // Current executing error of the request.
|
||||
exit bool // A bool marking whether current request is exited.
|
||||
exitAll bool // A bool marking whether current request is exited.
|
||||
parsedHost string // The parsed host name for current host used by GetHost function.
|
||||
clientIp string // The parsed client ip for current host used by GetClientIp function.
|
||||
bodyContent []byte // Request body content.
|
||||
@ -139,7 +139,7 @@ func (r *Request) Exit() {
|
||||
|
||||
// ExitAll exits executing of current and following HTTP handlers.
|
||||
func (r *Request) ExitAll() {
|
||||
r.exit = true
|
||||
r.exitAll = true
|
||||
panic(exceptionExitAll)
|
||||
}
|
||||
|
||||
@ -150,7 +150,7 @@ func (r *Request) ExitHook() {
|
||||
|
||||
// IsExited checks and returns whether current request is exited.
|
||||
func (r *Request) IsExited() bool {
|
||||
return r.exit
|
||||
return r.exitAll
|
||||
}
|
||||
|
||||
// GetHeader retrieves and returns the header value with given `key`.
|
||||
|
||||
@ -45,7 +45,7 @@ func Test_Log(t *testing.T) {
|
||||
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p))
|
||||
|
||||
t.Assert(client.GetContent(ctx, "/hello"), "hello")
|
||||
t.Assert(client.GetContent(ctx, "/error"), "custom error")
|
||||
t.Assert(client.GetContent(ctx, "/error"), "exception recovered: custom error")
|
||||
|
||||
var (
|
||||
logPath1 = gfile.Join(logDir, gtime.Now().Format("Y-m-d")+".log")
|
||||
|
||||
@ -709,6 +709,6 @@ func Test_Middleware_Panic(t *testing.T) {
|
||||
client := g.Client()
|
||||
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p))
|
||||
|
||||
t.Assert(client.GetContent(ctx, "/"), "error")
|
||||
t.Assert(client.GetContent(ctx, "/"), "exception recovered: error")
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,12 +9,13 @@ package gbuild
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime"
|
||||
|
||||
"github.com/gogf/gf/v2"
|
||||
"github.com/gogf/gf/v2/container/gvar"
|
||||
"github.com/gogf/gf/v2/encoding/gbase64"
|
||||
"github.com/gogf/gf/v2/internal/intlog"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@ -204,7 +204,12 @@ type printLineBriefInput struct {
|
||||
}
|
||||
|
||||
func (c *Command) printLineBrief(in printLineBriefInput) {
|
||||
for i, line := range gstr.SplitAndTrim(in.Brief, "\n") {
|
||||
briefArray := gstr.SplitAndTrim(in.Brief, "\n")
|
||||
if len(briefArray) == 0 {
|
||||
// If command brief is empty, it just prints its command name.
|
||||
briefArray = []string{""}
|
||||
}
|
||||
for i, line := range briefArray {
|
||||
var lineStr string
|
||||
if i == 0 {
|
||||
lineStr = fmt.Sprintf(
|
||||
|
||||
@ -245,17 +245,6 @@ func newCommandFromMethod(object interface{}, method reflect.Value) (command *Co
|
||||
// =============================================================================================
|
||||
command.FuncWithValue = func(ctx context.Context, parser *Parser) (out interface{}, err error) {
|
||||
ctx = context.WithValue(ctx, CtxKeyParser, parser)
|
||||
|
||||
defer func() {
|
||||
if exception := recover(); exception != nil {
|
||||
if v, ok := exception.(error); ok && gerror.HasStack(v) {
|
||||
err = v
|
||||
} else {
|
||||
err = gerror.New(`exception recovered:` + gconv.String(exception))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var (
|
||||
data = gconv.Map(parser.GetOptAll())
|
||||
argIndex = 0
|
||||
|
||||
@ -31,9 +31,17 @@ func (c *Command) Run(ctx context.Context) {
|
||||
func (c *Command) RunWithValue(ctx context.Context) (value interface{}) {
|
||||
value, err := c.RunWithValueError(ctx)
|
||||
if err != nil {
|
||||
if gerror.Code(err) == gcode.CodeNotFound {
|
||||
var (
|
||||
code = gerror.Code(err)
|
||||
detail = code.Detail()
|
||||
)
|
||||
if code.Code() == gcode.CodeNotFound.Code() {
|
||||
fmt.Printf("ERROR: %s\n", gstr.Trim(err.Error()))
|
||||
c.Print()
|
||||
if lastCmd, ok := detail.(*Command); ok {
|
||||
lastCmd.Print()
|
||||
} else {
|
||||
c.Print()
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("%+v\n", err)
|
||||
}
|
||||
@ -64,23 +72,34 @@ func (c *Command) RunWithValueError(ctx context.Context) (value interface{}, err
|
||||
args = args[1:]
|
||||
|
||||
// Find the matched command and run it.
|
||||
if subCommand, newCtx := c.searchCommand(ctx, args); subCommand != nil {
|
||||
return subCommand.doRun(newCtx, parser)
|
||||
lastCmd, foundCmd, newCtx := c.searchCommand(ctx, args)
|
||||
if foundCmd != nil {
|
||||
return foundCmd.doRun(newCtx, parser)
|
||||
}
|
||||
|
||||
// Print error and help command if no command found.
|
||||
err = gerror.NewCodef(
|
||||
gcode.CodeNotFound,
|
||||
`command "%s" not found for arguments "%s"`,
|
||||
gcode.WithCode(gcode.CodeNotFound, lastCmd),
|
||||
`command "%s" not found for command "%s", command line: %s`,
|
||||
gstr.Join(args, " "),
|
||||
c.Name,
|
||||
gstr.Join(os.Args, " "),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Command) doRun(ctx context.Context, parser *Parser) (value interface{}, err error) {
|
||||
ctx = context.WithValue(ctx, CtxKeyCommand, c)
|
||||
defer func() {
|
||||
if exception := recover(); exception != nil {
|
||||
if v, ok := exception.(error); ok && gerror.HasStack(v) {
|
||||
err = v
|
||||
} else {
|
||||
err = gerror.Newf(`exception recovered: %+v`, exception)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
ctx = context.WithValue(ctx, CtxKeyCommand, c)
|
||||
// Check built-in help command.
|
||||
if parser.ContainsOpt(helpOptionName) || parser.ContainsOpt(helpOptionNameShort) {
|
||||
if c.HelpFunc != nil {
|
||||
@ -154,12 +173,11 @@ func (c *Command) reParse(ctx context.Context, parser *Parser) (*Parser, error)
|
||||
}
|
||||
|
||||
// searchCommand recursively searches the command according given arguments.
|
||||
func (c *Command) searchCommand(ctx context.Context, args []string) (*Command, context.Context) {
|
||||
func (c *Command) searchCommand(ctx context.Context, args []string) (lastCmd, foundCmd *Command, newCtx context.Context) {
|
||||
if len(args) == 0 {
|
||||
return nil, ctx
|
||||
return c, nil, ctx
|
||||
}
|
||||
for _, cmd := range c.commands {
|
||||
|
||||
// Recursively searching the command.
|
||||
if cmd.Name == args[0] {
|
||||
leftArgs := args[1:]
|
||||
@ -167,16 +185,16 @@ func (c *Command) searchCommand(ctx context.Context, args []string) (*Command, c
|
||||
// it then gives all its left arguments to it.
|
||||
if cmd.hasArgumentFromIndex() {
|
||||
ctx = context.WithValue(ctx, CtxKeyArguments, leftArgs)
|
||||
return cmd, ctx
|
||||
return c, cmd, ctx
|
||||
}
|
||||
// Recursively searching.
|
||||
if len(leftArgs) == 0 {
|
||||
return cmd, ctx
|
||||
return c, cmd, ctx
|
||||
}
|
||||
return cmd.searchCommand(ctx, leftArgs)
|
||||
}
|
||||
}
|
||||
return nil, ctx
|
||||
return c, nil, ctx
|
||||
}
|
||||
|
||||
func (c *Command) hasArgumentFromIndex() bool {
|
||||
|
||||
@ -11,6 +11,7 @@ package gcmd_test
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
@ -222,3 +223,35 @@ gf build main.go -n my-app -v 1.0 -a amd64,386 -s linux,windows,darwin -p ./dock
|
||||
_ = c.RunWithError(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Command_NotFound(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
c0 := &gcmd.Command{
|
||||
Name: "c0",
|
||||
}
|
||||
c1 := &gcmd.Command{
|
||||
Name: "c1",
|
||||
FuncWithValue: func(ctx context.Context, parser *gcmd.Parser) (interface{}, error) {
|
||||
return nil, nil
|
||||
},
|
||||
}
|
||||
c21 := &gcmd.Command{
|
||||
Name: "c21",
|
||||
FuncWithValue: func(ctx context.Context, parser *gcmd.Parser) (interface{}, error) {
|
||||
return nil, nil
|
||||
},
|
||||
}
|
||||
c22 := &gcmd.Command{
|
||||
Name: "c22",
|
||||
FuncWithValue: func(ctx context.Context, parser *gcmd.Parser) (interface{}, error) {
|
||||
return nil, nil
|
||||
},
|
||||
}
|
||||
t.AssertNil(c0.AddCommand(c1))
|
||||
t.AssertNil(c1.AddCommand(c21, c22))
|
||||
|
||||
os.Args = []string{"c0", "c1", "c23", `--test="abc"`}
|
||||
err := c0.RunWithError(gctx.New())
|
||||
t.Assert(err.Error(), `command "c1 c23" not found for command "c0", command line: c0 c1 c23 --test="abc"`)
|
||||
})
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gtype"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
// Entry is the timing job.
|
||||
@ -45,9 +46,13 @@ func (entry *Entry) Run() {
|
||||
}
|
||||
go func() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
if err != panicExit {
|
||||
panic(err)
|
||||
if exception := recover(); exception != nil {
|
||||
if exception != panicExit {
|
||||
if v, ok := exception.(error); ok && gerror.HasStack(v) {
|
||||
panic(v)
|
||||
} else {
|
||||
panic(gerror.Newf(`exception recovered: %+v`, exception))
|
||||
}
|
||||
} else {
|
||||
entry.Close()
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user