mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
Merge branch 'master' of https://github.com/gogf/gf
This commit is contained in:
@ -7,6 +7,7 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -141,3 +142,21 @@ func FormatCmdKey(s string) string {
|
||||
func FormatEnvKey(s string) string {
|
||||
return strings.ToUpper(strings.Replace(s, ".", "_", -1))
|
||||
}
|
||||
|
||||
// StripSlashes un-quotes a quoted string by AddSlashes.
|
||||
func StripSlashes(str string) string {
|
||||
var buf bytes.Buffer
|
||||
l, skip := len(str), false
|
||||
for i, char := range str {
|
||||
if skip {
|
||||
skip = false
|
||||
} else if char == '\\' {
|
||||
if i+1 < l && str[i+1] == '\\' {
|
||||
skip = true
|
||||
}
|
||||
continue
|
||||
}
|
||||
buf.WriteRune(char)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
@ -13,9 +13,9 @@ import (
|
||||
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/container/gvar"
|
||||
"github.com/gogf/gf/v2/internal/command"
|
||||
"github.com/gogf/gf/v2/internal/intlog"
|
||||
"github.com/gogf/gf/v2/internal/utils"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/os/genv"
|
||||
)
|
||||
|
||||
@ -166,8 +166,8 @@ func (c *Config) GetWithCmd(ctx context.Context, pattern string, def ...interfac
|
||||
return nil, err
|
||||
}
|
||||
if value == nil {
|
||||
if v := gcmd.GetOpt(utils.FormatCmdKey(pattern)); v != nil {
|
||||
return v, nil
|
||||
if v := command.GetOpt(utils.FormatCmdKey(pattern)); v != "" {
|
||||
return gvar.New(v), nil
|
||||
}
|
||||
if len(def) > 0 {
|
||||
return gvar.New(def[0]), nil
|
||||
|
||||
@ -15,8 +15,8 @@ import (
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/command"
|
||||
"github.com/gogf/gf/v2/internal/intlog"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gfsnotify"
|
||||
"github.com/gogf/gf/v2/os/gres"
|
||||
@ -62,7 +62,7 @@ func NewAdapterFile(file ...string) (*AdapterFile, error) {
|
||||
name = file[0]
|
||||
} else {
|
||||
// Custom default configuration file name from command line or environment.
|
||||
if customFile := gcmd.GetOptWithEnv(commandEnvKeyForFile).String(); customFile != "" {
|
||||
if customFile := command.GetOptWithEnv(commandEnvKeyForFile); customFile != "" {
|
||||
name = customFile
|
||||
}
|
||||
}
|
||||
@ -72,7 +72,7 @@ func NewAdapterFile(file ...string) (*AdapterFile, error) {
|
||||
jsonMap: gmap.NewStrAnyMap(true),
|
||||
}
|
||||
// Customized dir path from env/cmd.
|
||||
if customPath := gcmd.GetOptWithEnv(commandEnvKeyForPath).String(); customPath != "" {
|
||||
if customPath := command.GetOptWithEnv(commandEnvKeyForPath); customPath != "" {
|
||||
if gfile.Exists(customPath) {
|
||||
if err = c.SetPath(customPath); err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -18,7 +18,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
CtxKeyParser gctx.StrKey = `GoFrameCommandParser`
|
||||
CtxKeyParser gctx.StrKey = `CtxKeyParser`
|
||||
CtxKeyCommand gctx.StrKey = `CtxKeyCommand`
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@ -28,8 +28,9 @@ type Command struct {
|
||||
Additional string // Additional info about this command, which will be appended to the end of help info.
|
||||
NeedArgs bool // NeedArgs specifies this command needs arguments.
|
||||
Strict bool // Strict parsing options, which means it returns error if invalid option given.
|
||||
Config string // Config node name, which also retrieves the values from config component along with command line.
|
||||
parent *Command // Parent command for internal usage.
|
||||
commands []Command // Sub commands of this command.
|
||||
commands []*Command // Sub commands of this command.
|
||||
}
|
||||
|
||||
// Function is a custom command callback function that is bound to a certain argument.
|
||||
@ -57,8 +58,18 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// CommandFromCtx retrieves and returns Command from context.
|
||||
func CommandFromCtx(ctx context.Context) *Command {
|
||||
if v := ctx.Value(CtxKeyCommand); v != nil {
|
||||
if p, ok := v.(*Command); ok {
|
||||
return p
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddCommand adds one or more sub-commands to current command.
|
||||
func (c *Command) AddCommand(commands ...Command) error {
|
||||
func (c *Command) AddCommand(commands ...*Command) error {
|
||||
for _, cmd := range commands {
|
||||
cmd.Name = gstr.Trim(cmd.Name)
|
||||
if cmd.Name == "" {
|
||||
@ -73,7 +84,7 @@ func (c *Command) AddCommand(commands ...Command) error {
|
||||
// AddObject adds one or more sub-commands to current command using struct object.
|
||||
func (c *Command) AddObject(objects ...interface{}) error {
|
||||
var (
|
||||
commands []Command
|
||||
commands []*Command
|
||||
)
|
||||
for _, object := range objects {
|
||||
rootCommand, err := NewFromObject(object)
|
||||
|
||||
@ -110,16 +110,22 @@ func (c *Command) Print() {
|
||||
// Example.
|
||||
if c.Examples != "" {
|
||||
buffer.WriteString("EXAMPLE\n")
|
||||
buffer.WriteString(prefix)
|
||||
buffer.WriteString(gstr.WordWrap(gstr.Trim(c.Examples), maxLineChars, "\n"+prefix))
|
||||
for _, line := range gstr.SplitAndTrim(c.Examples, "\n") {
|
||||
buffer.WriteString(prefix)
|
||||
buffer.WriteString(gstr.WordWrap(gstr.Trim(line), maxLineChars, "\n"+prefix))
|
||||
buffer.WriteString("\n")
|
||||
}
|
||||
buffer.WriteString("\n")
|
||||
}
|
||||
|
||||
// Description.
|
||||
if c.Description != "" {
|
||||
buffer.WriteString("DESCRIPTION\n")
|
||||
buffer.WriteString(prefix)
|
||||
buffer.WriteString(gstr.WordWrap(gstr.Trim(c.Description), maxLineChars, "\n"+prefix))
|
||||
for _, line := range gstr.SplitAndTrim(c.Description, "\n") {
|
||||
buffer.WriteString(prefix)
|
||||
buffer.WriteString(gstr.WordWrap(gstr.Trim(line), maxLineChars, "\n"+prefix))
|
||||
buffer.WriteString("\n")
|
||||
}
|
||||
buffer.WriteString("\n")
|
||||
}
|
||||
|
||||
|
||||
@ -37,7 +37,7 @@ var (
|
||||
)
|
||||
|
||||
// NewFromObject creates and returns a root command object using given object.
|
||||
func NewFromObject(object interface{}) (rootCmd Command, err error) {
|
||||
func NewFromObject(object interface{}) (rootCmd *Command, err error) {
|
||||
originValueAndKind := utils.OriginValueAndKind(object)
|
||||
if originValueAndKind.OriginKind != reflect.Struct {
|
||||
err = gerror.Newf(
|
||||
@ -55,12 +55,12 @@ func NewFromObject(object interface{}) (rootCmd Command, err error) {
|
||||
var (
|
||||
nameSet = gset.NewStrSet()
|
||||
rootCommandName = gmeta.Get(object, tagNameRoot).String()
|
||||
subCommands []Command
|
||||
subCommands []*Command
|
||||
)
|
||||
for i := 0; i < originValueAndKind.InputValue.NumMethod(); i++ {
|
||||
var (
|
||||
method = originValueAndKind.InputValue.Method(i)
|
||||
methodCommand Command
|
||||
methodCommand *Command
|
||||
)
|
||||
methodCommand, err = newCommandFromMethod(object, method)
|
||||
if err != nil {
|
||||
@ -93,7 +93,7 @@ func NewFromObject(object interface{}) (rootCmd Command, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func newCommandFromObjectMeta(object interface{}) (command Command, err error) {
|
||||
func newCommandFromObjectMeta(object interface{}) (command *Command, err error) {
|
||||
var (
|
||||
metaData = gmeta.Data(object)
|
||||
)
|
||||
@ -130,7 +130,7 @@ func newCommandFromObjectMeta(object interface{}) (command Command, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func newCommandFromMethod(object interface{}, method reflect.Value) (command Command, err error) {
|
||||
func newCommandFromMethod(object interface{}, method reflect.Value) (command *Command, err error) {
|
||||
var (
|
||||
reflectType = method.Type()
|
||||
)
|
||||
|
||||
@ -12,7 +12,10 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gcfg"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
)
|
||||
|
||||
// Run calls custom function that bound to this command.
|
||||
@ -53,6 +56,8 @@ func (c *Command) RunWithValue(ctx context.Context) (value interface{}, err erro
|
||||
}
|
||||
|
||||
func (c *Command) doRun(ctx context.Context, parser *Parser) (value interface{}, err error) {
|
||||
ctx = context.WithValue(ctx, CtxKeyCommand, c)
|
||||
|
||||
// Check built-in help command.
|
||||
if parser.ContainsOpt(helpOptionName) || parser.ContainsOpt(helpOptionNameShort) {
|
||||
if c.HelpFunc != nil {
|
||||
@ -84,7 +89,6 @@ func (c *Command) reParse(ctx context.Context, parser *Parser) (*Parser, error)
|
||||
if len(c.Options) == 0 {
|
||||
return parser, nil
|
||||
}
|
||||
|
||||
var (
|
||||
optionKey string
|
||||
supportedOptions = make(map[string]bool)
|
||||
@ -97,7 +101,30 @@ func (c *Command) reParse(ctx context.Context, parser *Parser) (*Parser, error)
|
||||
}
|
||||
supportedOptions[optionKey] = !option.Orphan
|
||||
}
|
||||
return Parse(supportedOptions, c.Strict)
|
||||
parser, err := Parse(supportedOptions, c.Strict)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Retrieve option values from config component if it has "config" tag.
|
||||
if c.Config != "" && gcfg.Instance().Available(ctx) {
|
||||
value, err := gcfg.Instance().Get(ctx, c.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
configMap := value.Map()
|
||||
for optionName, _ := range parser.passedOptions {
|
||||
// The command line has the high priority.
|
||||
if parser.ContainsOpt(optionName) {
|
||||
continue
|
||||
}
|
||||
// Merge the config value into parser.
|
||||
foundKey, foundValue := gutil.MapPossibleItemByKey(configMap, optionName)
|
||||
if foundKey != "" {
|
||||
parser.parsedOptions[optionName] = gconv.String(foundValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
return parser, nil
|
||||
}
|
||||
|
||||
// searchCommand recursively searches the command according given arguments.
|
||||
@ -109,13 +136,13 @@ func (c *Command) searchCommand(args []string) *Command {
|
||||
// If this command needs argument,
|
||||
// it then gives all its left arguments to it.
|
||||
if cmd.NeedArgs {
|
||||
return &cmd
|
||||
return cmd
|
||||
}
|
||||
// Recursively searching the command.
|
||||
if cmd.Name == args[0] {
|
||||
leftArgs := args[1:]
|
||||
if len(leftArgs) == 0 {
|
||||
return &cmd
|
||||
return cmd
|
||||
}
|
||||
return cmd.searchCommand(leftArgs)
|
||||
}
|
||||
|
||||
135
os/gcmd/gcmd_z_unit_feature_object2_test.go
Normal file
135
os/gcmd/gcmd_z_unit_feature_object2_test.go
Normal file
@ -0,0 +1,135 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// go test *.go -bench=".*" -benchmem
|
||||
|
||||
package gcmd_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
)
|
||||
|
||||
type commandBuild struct {
|
||||
g.Meta `name:"build" root:"build" args:"true" brief:"{commandBuildBrief}" dc:"{commandBuildDc}" eg:"{commandBuildEg}" ad:"{commandBuildAd}"`
|
||||
nodeNameInConfigFile string // nodeNameInConfigFile is the node name for compiler configurations in configuration file.
|
||||
packedGoFileName string // packedGoFileName specifies the file name for packing common folders into one single go file.
|
||||
}
|
||||
|
||||
const (
|
||||
commandBuildBrief = `cross-building go project for lots of platforms`
|
||||
commandBuildEg = `
|
||||
gf build main.go
|
||||
gf build main.go --pack public,template
|
||||
gf build main.go --cgo
|
||||
gf build main.go -m none
|
||||
gf build main.go -n my-app -a all -s all
|
||||
gf build main.go -n my-app -a amd64,386 -s linux -p .
|
||||
gf build main.go -n my-app -v 1.0 -a amd64,386 -s linux,windows,darwin -p ./docker/bin
|
||||
`
|
||||
commandBuildDc = `
|
||||
The "build" command is most commonly used command, which is designed as a powerful wrapper for
|
||||
"go build" command for convenience cross-compiling usage.
|
||||
It provides much more features for building binary:
|
||||
1. Cross-Compiling for many platforms and architectures.
|
||||
2. Configuration file support for compiling.
|
||||
3. Build-In Variables.
|
||||
`
|
||||
commandBuildAd = `
|
||||
PLATFORMS
|
||||
darwin amd64,arm64
|
||||
freebsd 386,amd64,arm
|
||||
linux 386,amd64,arm,arm64,ppc64,ppc64le,mips,mipsle,mips64,mips64le
|
||||
netbsd 386,amd64,arm
|
||||
openbsd 386,amd64,arm
|
||||
windows 386,amd64
|
||||
`
|
||||
// https://golang.google.cn/doc/install/source
|
||||
commandBuildPlatforms = `
|
||||
darwin amd64
|
||||
darwin arm64
|
||||
ios amd64
|
||||
ios arm64
|
||||
freebsd 386
|
||||
freebsd amd64
|
||||
freebsd arm
|
||||
linux 386
|
||||
linux amd64
|
||||
linux arm
|
||||
linux arm64
|
||||
linux ppc64
|
||||
linux ppc64le
|
||||
linux mips
|
||||
linux mipsle
|
||||
linux mips64
|
||||
linux mips64le
|
||||
netbsd 386
|
||||
netbsd amd64
|
||||
netbsd arm
|
||||
openbsd 386
|
||||
openbsd amd64
|
||||
openbsd arm
|
||||
windows 386
|
||||
windows amd64
|
||||
android arm
|
||||
dragonfly amd64
|
||||
plan9 386
|
||||
plan9 amd64
|
||||
solaris amd64
|
||||
`
|
||||
)
|
||||
|
||||
func init() {
|
||||
gtag.Sets(map[string]string{
|
||||
`commandBuildBrief`: commandBuildBrief,
|
||||
`commandBuildDc`: commandBuildDc,
|
||||
`commandBuildEg`: commandBuildEg,
|
||||
`commandBuildAd`: commandBuildAd,
|
||||
})
|
||||
}
|
||||
|
||||
type commandBuildInput struct {
|
||||
g.Meta `name:"build" config:"gfcli.build"`
|
||||
Name string `short:"n" name:"name" brief:"output binary name"`
|
||||
Version string `short:"v" name:"version" brief:"output binary version"`
|
||||
Arch string `short:"a" name:"arch" brief:"output binary architecture, multiple arch separated with ','"`
|
||||
System string `short:"s" name:"system" brief:"output binary system, multiple os separated with ','"`
|
||||
Output string `short:"o" name:"output" brief:"output binary path, used when building single binary file"`
|
||||
Path string `short:"p" name:"path" brief:"output binary directory path, default is './bin'" d:"./bin"`
|
||||
Extra string `short:"e" name:"extra" brief:"extra custom \"go build\" options"`
|
||||
Mod string `short:"m" name:"mod" brief:"like \"-mod\" option of \"go build\", use \"-m none\" to disable go module"`
|
||||
Cgo bool `short:"c" name:"cgo" brief:"enable or disable cgo feature, it's disabled in default" orphan:"true"`
|
||||
Pack string `name:"pack" brief:"pack specified folder into temporary go file before building and removes it after built"`
|
||||
}
|
||||
type commandBuildOutput struct{}
|
||||
|
||||
func (c commandBuild) Index(ctx context.Context, in commandBuildInput) (out *commandBuildOutput, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func TestNewFromObject(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
ctx = gctx.New()
|
||||
)
|
||||
cmd, err := gcmd.NewFromObject(commandBuild{
|
||||
nodeNameInConfigFile: "gfcli.build",
|
||||
packedGoFileName: "build_pack_data.go",
|
||||
})
|
||||
t.AssertNil(err)
|
||||
|
||||
os.Args = []string{"build", "-h"}
|
||||
err = cmd.Run(ctx)
|
||||
t.AssertNil(err)
|
||||
})
|
||||
}
|
||||
@ -81,7 +81,7 @@ func Test_Command(t *testing.T) {
|
||||
Name: "gf",
|
||||
}
|
||||
// env
|
||||
commandEnv := gcmd.Command{
|
||||
commandEnv := &gcmd.Command{
|
||||
Name: "env",
|
||||
Func: func(ctx context.Context, parser *gcmd.Parser) error {
|
||||
fmt.Println("env")
|
||||
@ -89,7 +89,7 @@ func Test_Command(t *testing.T) {
|
||||
},
|
||||
}
|
||||
// test
|
||||
commandTest := gcmd.Command{
|
||||
commandTest := &gcmd.Command{
|
||||
Name: "test",
|
||||
Brief: "test brief",
|
||||
Description: "test description current Golang environment variables",
|
||||
@ -145,7 +145,7 @@ func Test_Command_Print(t *testing.T) {
|
||||
Use 'gf help COMMAND' or 'gf COMMAND -h' for detail about a command, which has '...' in the tail of their comments.`,
|
||||
}
|
||||
// env
|
||||
commandEnv := gcmd.Command{
|
||||
commandEnv := &gcmd.Command{
|
||||
Name: "env",
|
||||
Brief: "show current Golang environment variables, long brief.long brief.long brief.long brief.long brief.long brief.long brief.long brief.",
|
||||
Description: "show current Golang environment variables",
|
||||
@ -157,7 +157,7 @@ Use 'gf help COMMAND' or 'gf COMMAND -h' for detail about a command, which has '
|
||||
g.Log().Fatal(ctx, err)
|
||||
}
|
||||
// get
|
||||
commandGet := gcmd.Command{
|
||||
commandGet := &gcmd.Command{
|
||||
Name: "get",
|
||||
Brief: "install or update GF to system in default...",
|
||||
Description: "show current Golang environment variables",
|
||||
@ -212,7 +212,7 @@ gf build main.go -n my-app -v 1.0 -a amd64,386 -s linux,windows,darwin -p ./dock
|
||||
return nil
|
||||
},
|
||||
}
|
||||
if err = c.AddCommand(commandBuild); err != nil {
|
||||
if err = c.AddCommand(&commandBuild); err != nil {
|
||||
g.Log().Fatal(ctx, err)
|
||||
}
|
||||
c.Run(ctx)
|
||||
|
||||
@ -12,8 +12,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gvar"
|
||||
"github.com/gogf/gf/v2/internal/command"
|
||||
"github.com/gogf/gf/v2/internal/utils"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
)
|
||||
|
||||
// All returns a copy of strings representing the environment,
|
||||
@ -94,8 +94,8 @@ func GetWithCmd(key string, def ...interface{}) *gvar.Var {
|
||||
return gvar.New(v)
|
||||
}
|
||||
cmdKey := utils.FormatCmdKey(key)
|
||||
if v := gcmd.GetOpt(cmdKey); !v.IsEmpty() {
|
||||
return v
|
||||
if v := command.GetOpt(cmdKey); v != "" {
|
||||
return gvar.New(v)
|
||||
}
|
||||
if len(def) > 0 {
|
||||
return gvar.New(def[0])
|
||||
|
||||
21
os/genv/genv_must.go
Normal file
21
os/genv/genv_must.go
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package genv
|
||||
|
||||
// MustSet performs as Set, but it panics if any error occurs.
|
||||
func MustSet(key, value string) {
|
||||
if err := Set(key, value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// MustRemove performs as Remove, but it panics if any error occurs.
|
||||
func MustRemove(key ...string) {
|
||||
if err := Remove(key...); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@ -84,7 +84,10 @@ func Uptime() time.Duration {
|
||||
// The command `cmd` reads the input parameters from input pipe `in`, and writes its output automatically
|
||||
// to output pipe `out`.
|
||||
func Shell(cmd string, out io.Writer, in io.Reader) error {
|
||||
p := NewProcess(getShell(), append([]string{getShellOption()}, parseCommand(cmd)...))
|
||||
p := NewProcess(
|
||||
getShell(),
|
||||
append([]string{getShellOption()}, parseCommand(cmd)...),
|
||||
)
|
||||
p.Stdin = in
|
||||
p.Stdout = out
|
||||
return p.Run()
|
||||
@ -92,18 +95,26 @@ func Shell(cmd string, out io.Writer, in io.Reader) error {
|
||||
|
||||
// ShellRun executes given command `cmd` synchronously and outputs the command result to the stdout.
|
||||
func ShellRun(cmd string) error {
|
||||
p := NewProcess(getShell(), append([]string{getShellOption()}, parseCommand(cmd)...))
|
||||
p := NewProcess(
|
||||
getShell(),
|
||||
append([]string{getShellOption()}, parseCommand(cmd)...),
|
||||
)
|
||||
return p.Run()
|
||||
}
|
||||
|
||||
// ShellExec executes given command `cmd` synchronously and returns the command result.
|
||||
func ShellExec(cmd string, environment ...[]string) (string, error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
p := NewProcess(getShell(), append([]string{getShellOption()}, parseCommand(cmd)...), environment...)
|
||||
var (
|
||||
buf = bytes.NewBuffer(nil)
|
||||
p = NewProcess(
|
||||
getShell(),
|
||||
append([]string{getShellOption()}, parseCommand(cmd)...),
|
||||
environment...,
|
||||
)
|
||||
)
|
||||
p.Stdout = buf
|
||||
p.Stderr = buf
|
||||
err := p.Run()
|
||||
return buf.String(), err
|
||||
return buf.String(), p.Run()
|
||||
}
|
||||
|
||||
// parseCommand parses command `cmd` into slice arguments.
|
||||
@ -147,7 +158,7 @@ func parseCommand(cmd string) (args []string) {
|
||||
return
|
||||
}
|
||||
|
||||
// getShell returns the shell command depending on current working operation system.
|
||||
// getShell returns the shell command depending on current working operating system.
|
||||
// It returns "cmd.exe" for windows, and "bash" or "sh" for others.
|
||||
func getShell() string {
|
||||
switch runtime.GOOS {
|
||||
@ -183,7 +194,7 @@ func getShellOption() string {
|
||||
|
||||
// SearchBinary searches the binary `file` in current working folder and PATH environment.
|
||||
func SearchBinary(file string) string {
|
||||
// Check if it's absolute path of exists at current working directory.
|
||||
// Check if it is absolute path of exists at current working directory.
|
||||
if gfile.Exists(file) {
|
||||
return file
|
||||
}
|
||||
@ -204,6 +215,7 @@ func SearchBinaryPath(file string) string {
|
||||
if gfile.Ext(file) != ".exe" {
|
||||
file += ".exe"
|
||||
}
|
||||
|
||||
default:
|
||||
array = gstr.SplitAndTrim(genv.Get("PATH").String(), ":")
|
||||
}
|
||||
|
||||
34
os/gproc/gproc_must.go
Normal file
34
os/gproc/gproc_must.go
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gproc
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// MustShell performs as Shell, but it panics if any error occurs.
|
||||
func MustShell(cmd string, out io.Writer, in io.Reader) {
|
||||
if err := Shell(cmd, out, in); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// MustShellRun performs as ShellRun, but it panics if any error occurs.
|
||||
func MustShellRun(cmd string) {
|
||||
if err := ShellRun(cmd); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// MustShellExec performs as ShellExec, but it panics if any error occurs.
|
||||
func MustShellExec(cmd string, environment ...[]string) string {
|
||||
result, err := ShellExec(cmd, environment...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -8,9 +8,9 @@ package gstructs
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/internal/utils"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
)
|
||||
|
||||
@ -18,10 +18,6 @@ const (
|
||||
jsonTagName = `json`
|
||||
)
|
||||
|
||||
var (
|
||||
tagMapRegex = regexp.MustCompile(`([\w\-]+):"(.+?)"`)
|
||||
)
|
||||
|
||||
// Tag returns the value associated with key in the tag string. If there is no
|
||||
// such key in the tag, Tag returns the empty string.
|
||||
func (f *Field) Tag(key string) string {
|
||||
@ -67,13 +63,10 @@ func (f *Field) TagStr() string {
|
||||
// TagMap returns all the tag of the field along with its value string as map.
|
||||
func (f *Field) TagMap() map[string]string {
|
||||
var (
|
||||
data = map[string]string{}
|
||||
match = tagMapRegex.FindAllStringSubmatch(f.TagStr(), -1)
|
||||
data = ParseTag(f.TagStr())
|
||||
)
|
||||
for _, m := range match {
|
||||
if len(m) == 3 {
|
||||
data[m[1]] = gtag.Parse(m[2])
|
||||
}
|
||||
for k, v := range data {
|
||||
data[k] = utils.StripSlashes(gtag.Parse(v))
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
@ -96,6 +96,8 @@ var (
|
||||
"sm": "summary",
|
||||
"des": "description",
|
||||
"dc": "description",
|
||||
"eg": "example",
|
||||
"egs": "examples",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ type Path struct {
|
||||
Parameters Parameters `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||
}
|
||||
|
||||
// Paths is specified by OpenAPI/Swagger standard version 3.0.
|
||||
// Paths are specified by OpenAPI/Swagger standard version 3.0.
|
||||
type Paths map[string]Path
|
||||
|
||||
const (
|
||||
|
||||
@ -442,20 +442,7 @@ func AddSlashes(str string) string {
|
||||
|
||||
// StripSlashes un-quotes a quoted string by AddSlashes.
|
||||
func StripSlashes(str string) string {
|
||||
var buf bytes.Buffer
|
||||
l, skip := len(str), false
|
||||
for i, char := range str {
|
||||
if skip {
|
||||
skip = false
|
||||
} else if char == '\\' {
|
||||
if i+1 < l && str[i+1] == '\\' {
|
||||
skip = true
|
||||
}
|
||||
continue
|
||||
}
|
||||
buf.WriteRune(char)
|
||||
}
|
||||
return buf.String()
|
||||
return utils.StripSlashes(str)
|
||||
}
|
||||
|
||||
// QuoteMeta returns a version of str with a backslash character (\)
|
||||
|
||||
@ -11,7 +11,7 @@ package gmode
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/debug/gdebug"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/internal/command"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
)
|
||||
|
||||
@ -58,7 +58,7 @@ func SetProduct() {
|
||||
func Mode() string {
|
||||
// If current mode is not set, do this auto check.
|
||||
if currentMode == NOT_SET {
|
||||
if v := gcmd.GetOptWithEnv(commandEnvKey).String(); v != "" {
|
||||
if v := command.GetOptWithEnv(commandEnvKey); v != "" {
|
||||
// Mode configured from command argument of environment.
|
||||
currentMode = v
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user