mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-05-08 04:20:59 -05:00
switch to go vendoring
This commit is contained in:
+91
@@ -0,0 +1,91 @@
|
||||
package cmdline
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// LineBuilder build command line string.
|
||||
// codes refer from strings.Builder
|
||||
type LineBuilder struct {
|
||||
buf []byte
|
||||
}
|
||||
|
||||
// NewBuilder create
|
||||
func NewBuilder(binFile string, args ...string) *LineBuilder {
|
||||
b := &LineBuilder{}
|
||||
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)
|
||||
}
|
||||
|
||||
// AddArgs to builder
|
||||
func (b *LineBuilder) AddArgs(args ...string) {
|
||||
b.AddArray(args)
|
||||
}
|
||||
|
||||
// AddArray to builder
|
||||
func (b *LineBuilder) AddArray(args []string) {
|
||||
for _, arg := range args {
|
||||
_, _ = b.WriteString(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, '"') {
|
||||
quote = '\''
|
||||
} else if a == "" || strings.ContainsRune(a, '\'') || strings.ContainsRune(a, ' ') {
|
||||
quote = '"'
|
||||
}
|
||||
|
||||
// add sep on first write.
|
||||
if b.buf != nil {
|
||||
b.buf = append(b.buf, ' ')
|
||||
}
|
||||
|
||||
// no quote char
|
||||
if quote == 0 {
|
||||
b.buf = append(b.buf, a...)
|
||||
return len(a) + 1, nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
// }
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
// Package cmdline provide quick build and parse cmd line string.
|
||||
package cmdline
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
package cmdline
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// LineParser struct
|
||||
// parse input command line to []string, such as cli os.Args
|
||||
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"`
|
||||
Line string
|
||||
// ParseEnv parse ENV var on the line.
|
||||
ParseEnv bool
|
||||
// the exploded nodes by space.
|
||||
nodes []string
|
||||
// the parsed args
|
||||
args []string
|
||||
}
|
||||
|
||||
// NewParser create
|
||||
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()
|
||||
}
|
||||
|
||||
// AlsoEnvParse input command line text to os.Args, will parse ENV var
|
||||
func (p *LineParser) AlsoEnvParse() []string {
|
||||
p.ParseEnv = true
|
||||
return p.Parse()
|
||||
}
|
||||
|
||||
// Parse input command line text to os.Args
|
||||
func (p *LineParser) Parse() []string {
|
||||
if p.parsed {
|
||||
return p.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 = 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
|
||||
}
|
||||
|
||||
// BinAndArgs get binName and args
|
||||
func (p *LineParser) BinAndArgs() (bin string, args []string) {
|
||||
p.Parse() // ensure parsed.
|
||||
|
||||
ln := len(p.args)
|
||||
if ln == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
bin = p.args[0]
|
||||
if ln > 1 {
|
||||
args = p.args[1:]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// NewExecCmd quick create exec.Cmd by cmdline string
|
||||
func (p *LineParser) NewExecCmd() *exec.Cmd {
|
||||
// parse get bin and args
|
||||
binName, args := p.BinAndArgs()
|
||||
|
||||
// create a new Cmd instance
|
||||
return exec.Command(binName, args...)
|
||||
}
|
||||
|
||||
func (p *LineParser) appendWithPrefix(node, prefix string) {
|
||||
if prefix != "" {
|
||||
p.args = append(p.args, prefix+" "+node)
|
||||
} else {
|
||||
p.args = append(p.args, node)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user