mirror of
https://github.com/eiblog/eiblog.git
synced 2026-02-23 06:32:28 +08:00
update vendor
This commit is contained in:
264
vendor/github.com/qiniu/x/cmdline.v7/cmdline.go
generated
vendored
Normal file
264
vendor/github.com/qiniu/x/cmdline.v7/cmdline.go
generated
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
package cmdline
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
. "qiniupkg.com/x/ctype.v7"
|
||||
)
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Shell 基础规则:
|
||||
|
||||
* 多行字符串:用 '...' 或 "..."。其中 " 会自动转义 $(var),而 ' 不会。
|
||||
* 普通字符串:用 [ \t] 分隔。转义符以 \ 开头。
|
||||
* 外部命令:`...`。
|
||||
|
||||
七牛规则:
|
||||
|
||||
* 外部命令: `...` 或 |...| 。
|
||||
* 多行字符串:用 '...' 或 ```\n...``` 或 ===\n...=== 不转义。用 "...",支持以 \ 开头的转义,也支持外部命令。
|
||||
* 普通字符串:用 [ \t] 分隔。转义符以 \ 开头,同时也支持外部命令。
|
||||
* 关于 $(var) 支持:每个命令自己执行 $(var) 的展开。不统一执行的原因是,在不同上下文需要不同的转义方式。
|
||||
|
||||
样例:
|
||||
|
||||
post http://rs.qiniu.com/delete/`base64 Bucket:Key`
|
||||
auth `qbox AccessKey SecretKey`
|
||||
ret 200
|
||||
|
||||
post http://rs.qiniu.com/batch
|
||||
auth qboxtest
|
||||
form op=/delete/`base64 Bucket:Key`&op=/delete/`base64 Bucket2:Key2`
|
||||
ret 200
|
||||
|
||||
post http://rs.qiniu.com/batch
|
||||
auth qboxtest
|
||||
form op=/delete/`base64 Bucket:Key`&op=/delete/`base64 Bucket:NotExistKey`
|
||||
ret 298
|
||||
json '[
|
||||
{"code": 200}, {"code": 612}
|
||||
]'
|
||||
equal $(code1) 200
|
||||
|
||||
// -------------------------------------------------------------------------*/
|
||||
|
||||
var (
|
||||
EOF = errors.New("end of file")
|
||||
ErrUnsupportedFeatureSubCmd = errors.New("unsupported feature: sub command")
|
||||
ErrUnsupportedFeatureMultiCmds = errors.New("unsupported feature: multi commands")
|
||||
ErrInvalidEscapeChar = errors.New("invalid escape char")
|
||||
ErrIncompleteStringExpectQuot = errors.New("incomplete string, expect \"")
|
||||
ErrIncompleteStringExpectSquot = errors.New("incomplete string, expect '")
|
||||
ErrIncompleteStringExpectBacktick = errors.New("incomplete string, expect ` or |")
|
||||
)
|
||||
|
||||
var (
|
||||
errEOL = errors.New("end of line")
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Skip(str string, typeMask uint32) string {
|
||||
|
||||
for i := 0; i < len(str); i++ {
|
||||
if !Is(typeMask, rune(str[i])) {
|
||||
return str[i:]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func Find(str string, typeMask uint32) (n int) {
|
||||
|
||||
for n = 0; n < len(str); n++ {
|
||||
if Is(typeMask, rune(str[n])) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// EOL = \r\n? | \n
|
||||
//
|
||||
func requireEOL(code string) (hasEOL bool, codeNext string) {
|
||||
|
||||
if strings.HasPrefix(code, "\r") {
|
||||
if strings.HasPrefix(code[1:], "\n") {
|
||||
return true, code[2:]
|
||||
}
|
||||
} else if !strings.HasPrefix(code, "\n") {
|
||||
return false, code
|
||||
}
|
||||
return true, code[1:]
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type Parser struct {
|
||||
ExecSub func(code string) (string, error)
|
||||
Escape func(c byte) string
|
||||
comment bool
|
||||
}
|
||||
|
||||
func NewParser() *Parser {
|
||||
|
||||
return &Parser{
|
||||
ExecSub: defaultExecSub,
|
||||
Escape: defaultEscape,
|
||||
}
|
||||
}
|
||||
|
||||
func defaultExecSub(code string) (string, error) {
|
||||
return "", ErrUnsupportedFeatureSubCmd
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const (
|
||||
endOfLine = EOL | SEMICOLON // [\r\n;]
|
||||
blanks = SPACE_BAR | TAB
|
||||
blankAndEOLs = SPACE_BAR | TAB | endOfLine
|
||||
)
|
||||
|
||||
const (
|
||||
endMask_QuotString = RDIV | BACKTICK | OR | QUOT // [\\`|"]
|
||||
endMask_NonquotString = RDIV | BACKTICK | OR | blankAndEOLs // [\\`| \t\r\n;]
|
||||
)
|
||||
|
||||
func (p *Parser) parseString(
|
||||
code string, endMask uint32) (item string, ok bool, codeNext string, err error) {
|
||||
|
||||
codeNext = code
|
||||
for {
|
||||
n := Find(codeNext, endMask)
|
||||
if n > 0 {
|
||||
item += codeNext[:n]
|
||||
ok = true
|
||||
}
|
||||
if len(codeNext) == n {
|
||||
codeNext = ""
|
||||
if endMask == endMask_QuotString {
|
||||
err = ErrIncompleteStringExpectQuot
|
||||
} else {
|
||||
err = EOF
|
||||
}
|
||||
return
|
||||
}
|
||||
switch codeNext[n] {
|
||||
case '\\':
|
||||
if len(codeNext) == n+1 {
|
||||
err = ErrInvalidEscapeChar
|
||||
return
|
||||
}
|
||||
item += p.Escape(codeNext[n+1])
|
||||
codeNext = codeNext[n+2:]
|
||||
case '`', '|':
|
||||
c := codeNext[n]
|
||||
codeNext = codeNext[n+1:]
|
||||
len := strings.IndexByte(codeNext, c)
|
||||
if len < 0 {
|
||||
err = ErrIncompleteStringExpectBacktick
|
||||
return
|
||||
}
|
||||
if !p.comment {
|
||||
valSub, errSub := p.ExecSub(codeNext[:len])
|
||||
if errSub != nil {
|
||||
err = errors.New("Exec `" + codeNext[:len] + "` failed: " + errSub.Error())
|
||||
return
|
||||
}
|
||||
item += valSub
|
||||
}
|
||||
codeNext = codeNext[len+1:]
|
||||
case '"':
|
||||
ok = true
|
||||
codeNext = codeNext[n+1:]
|
||||
return
|
||||
default:
|
||||
if Is(endOfLine, rune(codeNext[n])) {
|
||||
err = errEOL
|
||||
}
|
||||
codeNext = codeNext[n+1:]
|
||||
return
|
||||
}
|
||||
ok = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Parser) parseItem(
|
||||
code string, skipMask uint32) (item string, ok bool, codeNext string, err error) {
|
||||
|
||||
codeNext = Skip(code, skipMask)
|
||||
if len(codeNext) == 0 {
|
||||
err = EOF
|
||||
return
|
||||
}
|
||||
|
||||
switch codeNext[0] {
|
||||
case '"':
|
||||
return p.parseString(codeNext[1:], endMask_QuotString)
|
||||
case '\'':
|
||||
codeNext = codeNext[1:]
|
||||
len := strings.IndexByte(codeNext, '\'')
|
||||
if len < 0 {
|
||||
err = ErrIncompleteStringExpectSquot
|
||||
return
|
||||
}
|
||||
return codeNext[:len], true, codeNext[len+1:], nil
|
||||
default:
|
||||
if strings.HasPrefix(codeNext, "```") || strings.HasPrefix(codeNext, "===") {
|
||||
endMark := codeNext[:3]
|
||||
_, codeNext = requireEOL(codeNext[3:])
|
||||
len := strings.Index(codeNext, endMark)
|
||||
if len < 0 {
|
||||
err = errors.New("incomplete string, expect " + endMark)
|
||||
return
|
||||
}
|
||||
return codeNext[:len], true, codeNext[len+3:], nil
|
||||
}
|
||||
return p.parseString(codeNext, endMask_NonquotString)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) ParseCmd(cmdline string) (cmd []string, err error) {
|
||||
|
||||
cmd, _, err = p.ParseCode(cmdline)
|
||||
if err == EOF && len(cmd) > 0 {
|
||||
return cmd, nil
|
||||
}
|
||||
if err == nil {
|
||||
err = ErrUnsupportedFeatureMultiCmds
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Parser) ParseCode(code string) (cmd []string, codeNext string, err error) {
|
||||
|
||||
item, ok, codeNext, err := p.parseItem(code, blankAndEOLs)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
p.comment = strings.HasPrefix(item, "#")
|
||||
|
||||
cmd = append(cmd, item)
|
||||
for err == nil {
|
||||
item, ok, codeNext, err = p.parseItem(codeNext, blanks)
|
||||
if ok {
|
||||
cmd = append(cmd, item)
|
||||
}
|
||||
}
|
||||
if err == errEOL {
|
||||
err = nil
|
||||
}
|
||||
if p.comment {
|
||||
cmd = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
173
vendor/github.com/qiniu/x/cmdline.v7/cmdline_test.go
generated
vendored
Normal file
173
vendor/github.com/qiniu/x/cmdline.v7/cmdline_test.go
generated
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
package cmdline
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func equalErr(err error, errExp interface{}) bool {
|
||||
|
||||
if err == nil || errExp == nil {
|
||||
return err == nil && errExp == nil
|
||||
}
|
||||
return err.Error() == errExp.(string)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func TestComment(t *testing.T) {
|
||||
|
||||
execSub := false
|
||||
ctx := Parser{
|
||||
ExecSub: func(code string) (string, error) {
|
||||
execSub = true
|
||||
return "[" + code + "]", nil
|
||||
},
|
||||
Escape: func(c byte) string {
|
||||
return string(c)
|
||||
},
|
||||
}
|
||||
|
||||
cmd, codeNext, err := ctx.ParseCode("#abc `calc $(a)+$(b)`")
|
||||
if err != EOF || codeNext != "" {
|
||||
t.Fatal("ParseCode: eof is expected")
|
||||
}
|
||||
if execSub {
|
||||
t.Fatal("don't execSub")
|
||||
}
|
||||
if len(cmd) != 0 {
|
||||
t.Fatal("len(cmd) != 0")
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type caseParse struct {
|
||||
code string
|
||||
cmd []string
|
||||
codeNext string
|
||||
err interface{}
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
|
||||
cases := []caseParse{
|
||||
{
|
||||
code: ";b",
|
||||
cmd: []string{"b"},
|
||||
codeNext: "",
|
||||
err: "end of file",
|
||||
},
|
||||
{
|
||||
code: ";b;abc",
|
||||
cmd: []string{"b"},
|
||||
codeNext: "abc",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
code: "a`b`\\c",
|
||||
cmd: []string{"a[b]c"},
|
||||
codeNext: "",
|
||||
err: "end of file",
|
||||
},
|
||||
{
|
||||
code: "a`b`c 'c\\n`123`' \"c\\n\"",
|
||||
cmd: []string{"a[b]c", "c\\n`123`", "cn"},
|
||||
codeNext: "",
|
||||
err: "end of file",
|
||||
},
|
||||
{
|
||||
code: "auth qboxtest 'mac AccessKey SecretKey'",
|
||||
cmd: []string{"auth", "qboxtest", "mac AccessKey SecretKey"},
|
||||
codeNext: "",
|
||||
err: "end of file",
|
||||
},
|
||||
{
|
||||
code: "post http://rs.qiniu.com/delete/`base64 Bucket:Key`",
|
||||
cmd: []string{"post", "http://rs.qiniu.com/delete/[base64 Bucket:Key]"},
|
||||
codeNext: "",
|
||||
err: "end of file",
|
||||
},
|
||||
{
|
||||
code: "post http://rs.qiniu.com/delete `base64 Bucket:Key`",
|
||||
cmd: []string{"post", "http://rs.qiniu.com/delete", "[base64 Bucket:Key]"},
|
||||
codeNext: "",
|
||||
err: "end of file",
|
||||
},
|
||||
{
|
||||
code: "post http://rs.qiniu.com/delete/|base64 Bucket:Key|",
|
||||
cmd: []string{"post", "http://rs.qiniu.com/delete/[base64 Bucket:Key]"},
|
||||
codeNext: "",
|
||||
err: "end of file",
|
||||
},
|
||||
{
|
||||
code: `json '[
|
||||
{"code": 200}, {"code": 612}
|
||||
]'`,
|
||||
cmd: []string{"json", `[
|
||||
{"code": 200}, {"code": 612}
|
||||
]`},
|
||||
codeNext: "",
|
||||
err: "end of file",
|
||||
},
|
||||
{
|
||||
code: "auth qboxtest ```\nmac AccessKey SecretKey```",
|
||||
cmd: []string{"auth", "qboxtest", "mac AccessKey SecretKey"},
|
||||
codeNext: "",
|
||||
err: "end of file",
|
||||
},
|
||||
{
|
||||
code: "auth qboxtest ===\nmac AccessKey SecretKey```",
|
||||
cmd: []string{"auth", "qboxtest"},
|
||||
codeNext: "mac AccessKey SecretKey```",
|
||||
err: "incomplete string, expect ===",
|
||||
},
|
||||
{
|
||||
code: "auth qboxtest ===\rmac AccessKey SecretKey===",
|
||||
cmd: []string{"auth", "qboxtest", "mac AccessKey SecretKey"},
|
||||
codeNext: "",
|
||||
err: "end of file",
|
||||
},
|
||||
{
|
||||
code: "auth qboxtest ===\n\rmac AccessKey SecretKey===",
|
||||
cmd: []string{"auth", "qboxtest", "\rmac AccessKey SecretKey"},
|
||||
codeNext: "",
|
||||
err: "end of file",
|
||||
},
|
||||
{
|
||||
code: "auth qboxtest ===\r\n\nmac AccessKey SecretKey===",
|
||||
cmd: []string{"auth", "qboxtest", "\nmac AccessKey SecretKey"},
|
||||
codeNext: "",
|
||||
err: "end of file",
|
||||
},
|
||||
{
|
||||
code: "auth qboxtest ===mac AccessKey SecretKey===",
|
||||
cmd: []string{"auth", "qboxtest", "mac AccessKey SecretKey"},
|
||||
codeNext: "",
|
||||
err: "end of file",
|
||||
},
|
||||
}
|
||||
|
||||
ctx := Parser{
|
||||
ExecSub: func(code string) (string, error) {
|
||||
return "[" + code + "]", nil
|
||||
},
|
||||
Escape: func(c byte) string {
|
||||
return string(c)
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
cmd, codeNext, err := ctx.ParseCode(c.code)
|
||||
if !equalErr(err, c.err) {
|
||||
t.Fatal("Parse failed:", c, err)
|
||||
}
|
||||
if !reflect.DeepEqual(cmd, c.cmd) || codeNext != c.codeNext {
|
||||
t.Fatal("Parse failed:", c, cmd, codeNext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
98
vendor/github.com/qiniu/x/cmdline.v7/escape.go
generated
vendored
Normal file
98
vendor/github.com/qiniu/x/cmdline.v7/escape.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
package cmdline
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const (
|
||||
escTableBaseChar = '0'
|
||||
escTableLen = ('z' - escTableBaseChar + 1)
|
||||
)
|
||||
|
||||
var escTable = []byte{
|
||||
0, // 0 [48]
|
||||
49, // 1 [49]
|
||||
50, // 2 [50]
|
||||
51, // 3 [51]
|
||||
52, // 4 [52]
|
||||
53, // 5 [53]
|
||||
54, // 6 [54]
|
||||
55, // 7 [55]
|
||||
56, // 8 [56]
|
||||
57, // 9 [57]
|
||||
58, // : [58]
|
||||
59, // ; [59]
|
||||
60, // < [60]
|
||||
61, // = [61]
|
||||
62, // > [62]
|
||||
63, // ? [63]
|
||||
64, // @ [64]
|
||||
65, // A [65]
|
||||
66, // B [66]
|
||||
67, // C [67]
|
||||
68, // D [68]
|
||||
69, // E [69]
|
||||
70, // F [70]
|
||||
71, // G [71]
|
||||
72, // H [72]
|
||||
73, // I [73]
|
||||
74, // J [74]
|
||||
75, // K [75]
|
||||
76, // L [76]
|
||||
77, // M [77]
|
||||
78, // N [78]
|
||||
79, // O [79]
|
||||
80, // P [80]
|
||||
81, // Q [81]
|
||||
82, // R [82]
|
||||
83, // S [83]
|
||||
84, // T [84]
|
||||
85, // U [85]
|
||||
86, // V [86]
|
||||
87, // W [87]
|
||||
88, // X [88]
|
||||
89, // Y [89]
|
||||
90, // Z [90]
|
||||
91, // [ [91]
|
||||
92, // \ [92]
|
||||
93, // ] [93]
|
||||
94, // ^ [94]
|
||||
95, // _ [95]
|
||||
96, // ` [96]
|
||||
97, // a [97]
|
||||
98, // b [98]
|
||||
99, // c [99]
|
||||
100, // d [100]
|
||||
101, // e [101]
|
||||
102, // f [102]
|
||||
103, // g [103]
|
||||
104, // h [104]
|
||||
105, // i [105]
|
||||
106, // j [106]
|
||||
107, // k [107]
|
||||
108, // l [108]
|
||||
109, // m [109]
|
||||
'\n', // n [110]
|
||||
111, // o [111]
|
||||
112, // p [112]
|
||||
113, // q [113]
|
||||
'\r', // r [114]
|
||||
115, // s [115]
|
||||
'\t', // t [116]
|
||||
117, // u [117]
|
||||
118, // v [118]
|
||||
119, // w [119]
|
||||
120, // x [120]
|
||||
121, // y [121]
|
||||
122, // z [122]
|
||||
123, // { [123]
|
||||
}
|
||||
|
||||
func defaultEscape(c byte) string {
|
||||
|
||||
if c - escTableBaseChar < escTableLen {
|
||||
c = escTable[c - escTableBaseChar]
|
||||
}
|
||||
return string(c)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
41
vendor/github.com/qiniu/x/cmdline.v7/escape_test.go
generated
vendored
Normal file
41
vendor/github.com/qiniu/x/cmdline.v7/escape_test.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
package cmdline
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func TestEscape(t *testing.T) {
|
||||
|
||||
for i := 0; i < escTableBaseChar; i++ {
|
||||
checkEscapeChar(t, i, i)
|
||||
}
|
||||
|
||||
table := make([]int, escTableLen)
|
||||
for i := 0; i < escTableLen; i++ {
|
||||
table[i] = escTableBaseChar + i
|
||||
}
|
||||
table['0'-escTableBaseChar] = 0
|
||||
table['r'-escTableBaseChar] = '\r'
|
||||
table['t'-escTableBaseChar] = '\t'
|
||||
table['n'-escTableBaseChar] = '\n'
|
||||
for i := 0; i < escTableLen; i++ {
|
||||
checkEscapeChar(t, escTableBaseChar+i, table[i])
|
||||
}
|
||||
|
||||
for i := int(escTableBaseChar + escTableLen); i < 256; i++ {
|
||||
checkEscapeChar(t, i, i)
|
||||
}
|
||||
}
|
||||
|
||||
func checkEscapeChar(t *testing.T, i, exp int) {
|
||||
|
||||
ret := defaultEscape(byte(i))
|
||||
if ret != string(exp) {
|
||||
t.Fatal("escapeChar failed:", i)
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user