Bump github.com/gookit/config/v2 from 2.1.8 to 2.2.2
Bumps [github.com/gookit/config/v2](https://github.com/gookit/config) from 2.1.8 to 2.2.2. - [Release notes](https://github.com/gookit/config/releases) - [Commits](https://github.com/gookit/config/compare/v2.1.8...v2.2.2) --- updated-dependencies: - dependency-name: github.com/gookit/config/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
committed by
Ralf Haferkamp
parent
03045c5ccc
commit
5ebc596352
+36
-42
@@ -2,27 +2,28 @@ package cmdline
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/strutil"
|
||||
)
|
||||
|
||||
// LineBuilder build command line string.
|
||||
// codes refer from strings.Builder
|
||||
type LineBuilder struct {
|
||||
buf []byte
|
||||
strings.Builder
|
||||
}
|
||||
|
||||
// NewBuilder create
|
||||
func NewBuilder(binFile string, args ...string) *LineBuilder {
|
||||
b := &LineBuilder{}
|
||||
b.AddArg(binFile)
|
||||
|
||||
if binFile != "" {
|
||||
b.AddArg(binFile)
|
||||
}
|
||||
|
||||
b.AddArray(args)
|
||||
return b
|
||||
}
|
||||
|
||||
// LineBuild build command line string by given args.
|
||||
func LineBuild(binFile string, args []string) string {
|
||||
return NewBuilder(binFile, args...).String()
|
||||
}
|
||||
|
||||
// AddArg to builder
|
||||
func (b *LineBuilder) AddArg(arg string) {
|
||||
_, _ = b.WriteString(arg)
|
||||
@@ -40,52 +41,45 @@ func (b *LineBuilder) AddArray(args []string) {
|
||||
}
|
||||
}
|
||||
|
||||
// AddAny args to builder
|
||||
func (b *LineBuilder) AddAny(args ...any) {
|
||||
for _, arg := range args {
|
||||
_, _ = b.WriteString(strutil.SafeString(arg))
|
||||
}
|
||||
}
|
||||
|
||||
// WriteString arg string to the builder, will auto quote special string.
|
||||
// refer strconv.Quote()
|
||||
func (b *LineBuilder) WriteString(a string) (int, error) {
|
||||
var quote byte
|
||||
if strings.ContainsRune(a, '"') {
|
||||
if pos := strings.IndexByte(a, '"'); pos > -1 {
|
||||
quote = '\''
|
||||
} else if a == "" || strings.ContainsRune(a, '\'') || strings.ContainsRune(a, ' ') {
|
||||
// fix: a = `--pretty=format:"one two three"`
|
||||
if pos > 0 && '"' == a[len(a)-1] {
|
||||
quote = 0
|
||||
}
|
||||
} else if pos := strings.IndexByte(a, '\''); pos > -1 {
|
||||
quote = '"'
|
||||
// fix: a = "--pretty=format:'one two three'"
|
||||
if pos > 0 && '\'' == a[len(a)-1] {
|
||||
quote = 0
|
||||
}
|
||||
} else if a == "" || strings.ContainsRune(a, ' ') {
|
||||
quote = '"'
|
||||
}
|
||||
|
||||
// add sep on first write.
|
||||
if b.buf != nil {
|
||||
b.buf = append(b.buf, ' ')
|
||||
// add sep on not-first write.
|
||||
if b.Len() != 0 {
|
||||
_ = b.WriteByte(' ')
|
||||
}
|
||||
|
||||
// no quote char
|
||||
// no quote char OR not need quote
|
||||
if quote == 0 {
|
||||
b.buf = append(b.buf, a...)
|
||||
return len(a) + 1, nil
|
||||
return b.Builder.WriteString(a)
|
||||
}
|
||||
|
||||
b.buf = append(b.buf, quote) // add start quote
|
||||
b.buf = append(b.buf, a...)
|
||||
b.buf = append(b.buf, quote) // add end quote
|
||||
return len(a) + 3, nil
|
||||
_ = b.WriteByte(quote) // add start quote
|
||||
n, err := b.Builder.WriteString(a)
|
||||
_ = b.WriteByte(quote) // add end quote
|
||||
return n, err
|
||||
}
|
||||
|
||||
// String to command line string
|
||||
func (b *LineBuilder) String() string {
|
||||
return string(b.buf)
|
||||
}
|
||||
|
||||
// Len of the builder
|
||||
func (b *LineBuilder) Len() int {
|
||||
return len(b.buf)
|
||||
}
|
||||
|
||||
// Reset builder
|
||||
func (b *LineBuilder) Reset() {
|
||||
b.buf = nil
|
||||
}
|
||||
|
||||
// grow copies the buffer to a new, larger buffer so that there are at least n
|
||||
// bytes of capacity beyond len(b.buf).
|
||||
// func (b *LineBuilder) grow(n int) {
|
||||
// buf := make([]byte, len(b.buf), 2*cap(b.buf)+n)
|
||||
// copy(buf, b.buf)
|
||||
// b.buf = buf
|
||||
// }
|
||||
|
||||
+10
@@ -1,2 +1,12 @@
|
||||
// Package cmdline provide quick build and parse cmd line string.
|
||||
package cmdline
|
||||
|
||||
// LineBuild build command line string by given args.
|
||||
func LineBuild(binFile string, args []string) string {
|
||||
return NewBuilder(binFile, args...).String()
|
||||
}
|
||||
|
||||
// ParseLine input command line text. alias of the StringToOSArgs()
|
||||
func ParseLine(line string) []string {
|
||||
return NewParser(line).Parse()
|
||||
}
|
||||
|
||||
+115
-100
@@ -1,9 +1,13 @@
|
||||
package cmdline
|
||||
|
||||
import (
|
||||
"os"
|
||||
"bytes"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
"github.com/gookit/goutil/strutil"
|
||||
)
|
||||
|
||||
// LineParser struct
|
||||
@@ -11,7 +15,7 @@ import (
|
||||
type LineParser struct {
|
||||
parsed bool
|
||||
// Line the full input command line text
|
||||
// eg `kite top sub -a "the a message" --foo val1 --bar "val 2"`
|
||||
// eg `kite top sub -a "this is a message" --foo val1 --bar "val 2"`
|
||||
Line string
|
||||
// ParseEnv parse ENV var on the line.
|
||||
ParseEnv bool
|
||||
@@ -19,6 +23,11 @@ type LineParser struct {
|
||||
nodes []string
|
||||
// the parsed args
|
||||
args []string
|
||||
|
||||
// temp value
|
||||
quoteChar byte
|
||||
quoteIndex int // if > 0, mark is not on start
|
||||
tempNode bytes.Buffer
|
||||
}
|
||||
|
||||
// NewParser create
|
||||
@@ -26,11 +35,10 @@ func NewParser(line string) *LineParser {
|
||||
return &LineParser{Line: line}
|
||||
}
|
||||
|
||||
// ParseLine input command line text. alias of the StringToOSArgs()
|
||||
func ParseLine(line string) []string {
|
||||
p := &LineParser{Line: line}
|
||||
|
||||
return p.Parse()
|
||||
// WithParseEnv with parse ENV var
|
||||
func (p *LineParser) WithParseEnv() *LineParser {
|
||||
p.ParseEnv = true
|
||||
return p
|
||||
}
|
||||
|
||||
// AlsoEnvParse input command line text to os.Args, will parse ENV var
|
||||
@@ -39,90 +47,13 @@ func (p *LineParser) AlsoEnvParse() []string {
|
||||
return p.Parse()
|
||||
}
|
||||
|
||||
// Parse input command line text to os.Args
|
||||
func (p *LineParser) Parse() []string {
|
||||
if p.parsed {
|
||||
return p.args
|
||||
}
|
||||
// NewExecCmd quick create exec.Cmd by cmdline string
|
||||
func (p *LineParser) NewExecCmd() *exec.Cmd {
|
||||
// parse get bin and args
|
||||
binName, args := p.BinAndArgs()
|
||||
|
||||
p.parsed = true
|
||||
p.Line = strings.TrimSpace(p.Line)
|
||||
if p.Line == "" {
|
||||
return p.args
|
||||
}
|
||||
|
||||
// enable parse Env var
|
||||
if p.ParseEnv {
|
||||
p.Line = os.ExpandEnv(p.Line)
|
||||
}
|
||||
|
||||
p.nodes = strings.Split(p.Line, " ")
|
||||
if len(p.nodes) == 1 {
|
||||
p.args = p.nodes
|
||||
return p.args
|
||||
}
|
||||
|
||||
// temp value
|
||||
var quoteChar, fullNode string
|
||||
for _, node := range p.nodes {
|
||||
if node == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
nodeLen := len(node)
|
||||
start, end := node[:1], node[nodeLen-1:]
|
||||
|
||||
var clearTemp bool
|
||||
if start == "'" || start == `"` {
|
||||
noStart := node[1:]
|
||||
if quoteChar == "" { // start
|
||||
// only one words. eg: `-m "msg"`
|
||||
if end == start {
|
||||
p.args = append(p.args, node[1:nodeLen-1])
|
||||
continue
|
||||
}
|
||||
|
||||
fullNode += noStart
|
||||
quoteChar = start
|
||||
} else if quoteChar == start { // invalid. eg: `-m "this is "message` `-m "this is "message"`
|
||||
p.appendWithPrefix(strings.Trim(node, quoteChar), fullNode)
|
||||
clearTemp = true // clear temp value
|
||||
} else if quoteChar == end { // eg: `"has inner 'quote'"`
|
||||
p.appendWithPrefix(node[:nodeLen-1], fullNode)
|
||||
clearTemp = true // clear temp value
|
||||
} else { // goon. eg: `-m "the 'some' message"`
|
||||
fullNode += " " + node
|
||||
}
|
||||
} else if end == "'" || end == `"` {
|
||||
noEnd := node[:nodeLen-1]
|
||||
if quoteChar == "" { // end
|
||||
p.appendWithPrefix(noEnd, fullNode)
|
||||
clearTemp = true // clear temp value
|
||||
} else if quoteChar == end { // end
|
||||
p.appendWithPrefix(noEnd, fullNode)
|
||||
clearTemp = true // clear temp value
|
||||
} else { // goon. eg: `-m "the 'some' message"`
|
||||
fullNode += " " + node
|
||||
}
|
||||
} else {
|
||||
if quoteChar != "" {
|
||||
fullNode += " " + node
|
||||
} else {
|
||||
p.args = append(p.args, node)
|
||||
}
|
||||
}
|
||||
|
||||
// clear temp value
|
||||
if clearTemp {
|
||||
quoteChar, fullNode = "", ""
|
||||
}
|
||||
}
|
||||
|
||||
if fullNode != "" {
|
||||
p.args = append(p.args, fullNode)
|
||||
}
|
||||
|
||||
return p.args
|
||||
// create a new Cmd instance
|
||||
return exec.Command(binName, args...)
|
||||
}
|
||||
|
||||
// BinAndArgs get binName and args
|
||||
@@ -141,19 +72,103 @@ func (p *LineParser) BinAndArgs() (bin string, args []string) {
|
||||
return
|
||||
}
|
||||
|
||||
// NewExecCmd quick create exec.Cmd by cmdline string
|
||||
func (p *LineParser) NewExecCmd() *exec.Cmd {
|
||||
// parse get bin and args
|
||||
binName, args := p.BinAndArgs()
|
||||
// Parse input command line text to os.Args
|
||||
func (p *LineParser) Parse() []string {
|
||||
if p.parsed {
|
||||
return p.args
|
||||
}
|
||||
|
||||
// create a new Cmd instance
|
||||
return exec.Command(binName, args...)
|
||||
p.parsed = true
|
||||
p.Line = strings.TrimSpace(p.Line)
|
||||
if p.Line == "" {
|
||||
return p.args
|
||||
}
|
||||
|
||||
// enable parse Env var
|
||||
if p.ParseEnv {
|
||||
p.Line = comfunc.ParseEnvVar(p.Line, nil)
|
||||
}
|
||||
|
||||
p.nodes = strings.Split(p.Line, " ")
|
||||
if len(p.nodes) == 1 {
|
||||
p.args = p.nodes
|
||||
return p.args
|
||||
}
|
||||
|
||||
for i := 0; i < len(p.nodes); i++ {
|
||||
node := p.nodes[i]
|
||||
if node == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
p.parseNode(node)
|
||||
}
|
||||
|
||||
p.nodes = p.nodes[:0]
|
||||
if p.tempNode.Len() > 0 {
|
||||
p.appendTempNode()
|
||||
}
|
||||
return p.args
|
||||
}
|
||||
|
||||
func (p *LineParser) appendWithPrefix(node, prefix string) {
|
||||
if prefix != "" {
|
||||
p.args = append(p.args, prefix+" "+node)
|
||||
func (p *LineParser) parseNode(node string) {
|
||||
maxIdx := len(node) - 1
|
||||
start, end := node[0], node[maxIdx]
|
||||
|
||||
// in quotes
|
||||
if p.quoteChar != 0 {
|
||||
p.tempNode.WriteByte(' ')
|
||||
|
||||
// end quotes
|
||||
if end == p.quoteChar {
|
||||
if p.quoteIndex > 0 {
|
||||
p.tempNode.WriteString(node) // eg: node="--pretty=format:'one two'"
|
||||
} else {
|
||||
p.tempNode.WriteString(node[:maxIdx]) // remove last quote
|
||||
}
|
||||
p.appendTempNode()
|
||||
} else { // goon ... write to temp node
|
||||
p.tempNode.WriteString(node)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// quote start
|
||||
if start == comdef.DoubleQuote || start == comdef.SingleQuote {
|
||||
// only one words. eg: `-m "msg"`
|
||||
if end == start {
|
||||
p.args = append(p.args, node[1:maxIdx])
|
||||
return
|
||||
}
|
||||
|
||||
p.quoteChar = start
|
||||
p.tempNode.WriteString(node[1:])
|
||||
} else if end == comdef.DoubleQuote || end == comdef.SingleQuote {
|
||||
p.args = append(p.args, node) // only one node: `msg"`
|
||||
} else {
|
||||
p.args = append(p.args, node)
|
||||
// eg: --pretty=format:'one two three'
|
||||
if strutil.ContainsByte(node, comdef.DoubleQuote) {
|
||||
p.quoteIndex = 1 // mark is not on start
|
||||
p.quoteChar = comdef.DoubleQuote
|
||||
} else if strutil.ContainsByte(node, comdef.SingleQuote) {
|
||||
p.quoteIndex = 1
|
||||
p.quoteChar = comdef.SingleQuote
|
||||
}
|
||||
|
||||
// in quote, append to temp-node
|
||||
if p.quoteChar != 0 {
|
||||
p.tempNode.WriteString(node)
|
||||
} else {
|
||||
p.args = append(p.args, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *LineParser) appendTempNode() {
|
||||
p.args = append(p.args, p.tempNode.String())
|
||||
|
||||
// reset context value
|
||||
p.quoteChar = 0
|
||||
p.quoteIndex = 0
|
||||
p.tempNode.Reset()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user