improve package gcmd

This commit is contained in:
John Guo 2021-12-08 19:50:28 +08:00
parent 4f0b45aeac
commit 01930c9899
6 changed files with 170 additions and 30 deletions

View File

@ -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()
}

View File

@ -75,7 +75,7 @@ func (c *Command) Print() {
// Option.
if len(options) > 0 {
buffer.WriteString("OPTIONS\n")
buffer.WriteString("OPTION\n")
var (
nameStr string
maxSpaceLength = 0
@ -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")
}

View 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)
})
}

View File

@ -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
}

View File

@ -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 (\)