mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-07-09 21:17:09 +08:00
Use compose-spec parser
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
16
vendor/github.com/mattn/go-shellwords/.travis.yml
generated
vendored
Normal file
16
vendor/github.com/mattn/go-shellwords/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
arch:
|
||||
- amd64
|
||||
- ppc64le
|
||||
language: go
|
||||
sudo: false
|
||||
go:
|
||||
- tip
|
||||
|
||||
before_install:
|
||||
- go get -t -v ./...
|
||||
|
||||
script:
|
||||
- ./go.test.sh
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
21
vendor/github.com/mattn/go-shellwords/LICENSE
generated
vendored
Normal file
21
vendor/github.com/mattn/go-shellwords/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Yasuhiro Matsumoto
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
55
vendor/github.com/mattn/go-shellwords/README.md
generated
vendored
Normal file
55
vendor/github.com/mattn/go-shellwords/README.md
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
# go-shellwords
|
||||
|
||||
[](https://codecov.io/gh/mattn/go-shellwords)
|
||||
[](https://travis-ci.org/mattn/go-shellwords)
|
||||
[](https://pkg.go.dev/github.com/mattn/go-shellwords)
|
||||
[](https://github.com/mattn/go-shellwords/actions)
|
||||
|
||||
Parse line as shell words.
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
args, err := shellwords.Parse("./foo --bar=baz")
|
||||
// args should be ["./foo", "--bar=baz"]
|
||||
```
|
||||
|
||||
```go
|
||||
envs, args, err := shellwords.ParseWithEnvs("FOO=foo BAR=baz ./foo --bar=baz")
|
||||
// envs should be ["FOO=foo", "BAR=baz"]
|
||||
// args should be ["./foo", "--bar=baz"]
|
||||
```
|
||||
|
||||
```go
|
||||
os.Setenv("FOO", "bar")
|
||||
p := shellwords.NewParser()
|
||||
p.ParseEnv = true
|
||||
args, err := p.Parse("./foo $FOO")
|
||||
// args should be ["./foo", "bar"]
|
||||
```
|
||||
|
||||
```go
|
||||
p := shellwords.NewParser()
|
||||
p.ParseBacktick = true
|
||||
args, err := p.Parse("./foo `echo $SHELL`")
|
||||
// args should be ["./foo", "/bin/bash"]
|
||||
```
|
||||
|
||||
```go
|
||||
shellwords.ParseBacktick = true
|
||||
p := shellwords.NewParser()
|
||||
args, err := p.Parse("./foo `echo $SHELL`")
|
||||
// args should be ["./foo", "/bin/bash"]
|
||||
```
|
||||
|
||||
# Thanks
|
||||
|
||||
This is based on cpan module [Parse::CommandLine](https://metacpan.org/pod/Parse::CommandLine).
|
||||
|
||||
# License
|
||||
|
||||
under the MIT License: http://mattn.mit-license.org/2017
|
||||
|
||||
# Author
|
||||
|
||||
Yasuhiro Matsumoto (a.k.a mattn)
|
3
vendor/github.com/mattn/go-shellwords/go.mod
generated
vendored
Normal file
3
vendor/github.com/mattn/go-shellwords/go.mod
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
module github.com/mattn/go-shellwords
|
||||
|
||||
go 1.13
|
12
vendor/github.com/mattn/go-shellwords/go.test.sh
generated
vendored
Normal file
12
vendor/github.com/mattn/go-shellwords/go.test.sh
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
echo "" > coverage.txt
|
||||
|
||||
for d in $(go list ./... | grep -v vendor); do
|
||||
go test -coverprofile=profile.out -covermode=atomic "$d"
|
||||
if [ -f profile.out ]; then
|
||||
cat profile.out >> coverage.txt
|
||||
rm profile.out
|
||||
fi
|
||||
done
|
317
vendor/github.com/mattn/go-shellwords/shellwords.go
generated
vendored
Normal file
317
vendor/github.com/mattn/go-shellwords/shellwords.go
generated
vendored
Normal file
@ -0,0 +1,317 @@
|
||||
package shellwords
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var (
|
||||
ParseEnv bool = false
|
||||
ParseBacktick bool = false
|
||||
)
|
||||
|
||||
func isSpace(r rune) bool {
|
||||
switch r {
|
||||
case ' ', '\t', '\r', '\n':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func replaceEnv(getenv func(string) string, s string) string {
|
||||
if getenv == nil {
|
||||
getenv = os.Getenv
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
rs := []rune(s)
|
||||
for i := 0; i < len(rs); i++ {
|
||||
r := rs[i]
|
||||
if r == '\\' {
|
||||
i++
|
||||
if i == len(rs) {
|
||||
break
|
||||
}
|
||||
buf.WriteRune(rs[i])
|
||||
continue
|
||||
} else if r == '$' {
|
||||
i++
|
||||
if i == len(rs) {
|
||||
buf.WriteRune(r)
|
||||
break
|
||||
}
|
||||
if rs[i] == 0x7b {
|
||||
i++
|
||||
p := i
|
||||
for ; i < len(rs); i++ {
|
||||
r = rs[i]
|
||||
if r == '\\' {
|
||||
i++
|
||||
if i == len(rs) {
|
||||
return s
|
||||
}
|
||||
continue
|
||||
}
|
||||
if r == 0x7d || (!unicode.IsLetter(r) && r != '_' && !unicode.IsDigit(r)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if r != 0x7d {
|
||||
return s
|
||||
}
|
||||
if i > p {
|
||||
buf.WriteString(getenv(s[p:i]))
|
||||
}
|
||||
} else {
|
||||
p := i
|
||||
for ; i < len(rs); i++ {
|
||||
r := rs[i]
|
||||
if r == '\\' {
|
||||
i++
|
||||
if i == len(rs) {
|
||||
return s
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !unicode.IsLetter(r) && r != '_' && !unicode.IsDigit(r) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if i > p {
|
||||
buf.WriteString(getenv(s[p:i]))
|
||||
i--
|
||||
} else {
|
||||
buf.WriteString(s[p:])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buf.WriteRune(r)
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
type Parser struct {
|
||||
ParseEnv bool
|
||||
ParseBacktick bool
|
||||
Position int
|
||||
Dir string
|
||||
|
||||
// If ParseEnv is true, use this for getenv.
|
||||
// If nil, use os.Getenv.
|
||||
Getenv func(string) string
|
||||
}
|
||||
|
||||
func NewParser() *Parser {
|
||||
return &Parser{
|
||||
ParseEnv: ParseEnv,
|
||||
ParseBacktick: ParseBacktick,
|
||||
Position: 0,
|
||||
Dir: "",
|
||||
}
|
||||
}
|
||||
|
||||
type argType int
|
||||
|
||||
const (
|
||||
argNo argType = iota
|
||||
argSingle
|
||||
argQuoted
|
||||
)
|
||||
|
||||
func (p *Parser) Parse(line string) ([]string, error) {
|
||||
args := []string{}
|
||||
buf := ""
|
||||
var escaped, doubleQuoted, singleQuoted, backQuote, dollarQuote bool
|
||||
backtick := ""
|
||||
|
||||
pos := -1
|
||||
got := argNo
|
||||
|
||||
i := -1
|
||||
loop:
|
||||
for _, r := range line {
|
||||
i++
|
||||
if escaped {
|
||||
buf += string(r)
|
||||
escaped = false
|
||||
got = argSingle
|
||||
continue
|
||||
}
|
||||
|
||||
if r == '\\' {
|
||||
if singleQuoted {
|
||||
buf += string(r)
|
||||
} else {
|
||||
escaped = true
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if isSpace(r) {
|
||||
if singleQuoted || doubleQuoted || backQuote || dollarQuote {
|
||||
buf += string(r)
|
||||
backtick += string(r)
|
||||
} else if got != argNo {
|
||||
if p.ParseEnv {
|
||||
if got == argSingle {
|
||||
parser := &Parser{ParseEnv: false, ParseBacktick: false, Position: 0, Dir: p.Dir}
|
||||
strs, err := parser.Parse(replaceEnv(p.Getenv, buf))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args = append(args, strs...)
|
||||
} else {
|
||||
args = append(args, replaceEnv(p.Getenv, buf))
|
||||
}
|
||||
} else {
|
||||
args = append(args, buf)
|
||||
}
|
||||
buf = ""
|
||||
got = argNo
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
switch r {
|
||||
case '`':
|
||||
if !singleQuoted && !doubleQuoted && !dollarQuote {
|
||||
if p.ParseBacktick {
|
||||
if backQuote {
|
||||
out, err := shellRun(backtick, p.Dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf = buf[:len(buf)-len(backtick)] + out
|
||||
}
|
||||
backtick = ""
|
||||
backQuote = !backQuote
|
||||
continue
|
||||
}
|
||||
backtick = ""
|
||||
backQuote = !backQuote
|
||||
}
|
||||
case ')':
|
||||
if !singleQuoted && !doubleQuoted && !backQuote {
|
||||
if p.ParseBacktick {
|
||||
if dollarQuote {
|
||||
out, err := shellRun(backtick, p.Dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf = buf[:len(buf)-len(backtick)-2] + out
|
||||
}
|
||||
backtick = ""
|
||||
dollarQuote = !dollarQuote
|
||||
continue
|
||||
}
|
||||
backtick = ""
|
||||
dollarQuote = !dollarQuote
|
||||
}
|
||||
case '(':
|
||||
if !singleQuoted && !doubleQuoted && !backQuote {
|
||||
if !dollarQuote && strings.HasSuffix(buf, "$") {
|
||||
dollarQuote = true
|
||||
buf += "("
|
||||
continue
|
||||
} else {
|
||||
return nil, errors.New("invalid command line string")
|
||||
}
|
||||
}
|
||||
case '"':
|
||||
if !singleQuoted && !dollarQuote {
|
||||
if doubleQuoted {
|
||||
got = argQuoted
|
||||
}
|
||||
doubleQuoted = !doubleQuoted
|
||||
continue
|
||||
}
|
||||
case '\'':
|
||||
if !doubleQuoted && !dollarQuote {
|
||||
if singleQuoted {
|
||||
got = argQuoted
|
||||
}
|
||||
singleQuoted = !singleQuoted
|
||||
continue
|
||||
}
|
||||
case ';', '&', '|', '<', '>':
|
||||
if !(escaped || singleQuoted || doubleQuoted || backQuote || dollarQuote) {
|
||||
if r == '>' && len(buf) > 0 {
|
||||
if c := buf[0]; '0' <= c && c <= '9' {
|
||||
i -= 1
|
||||
got = argNo
|
||||
}
|
||||
}
|
||||
pos = i
|
||||
break loop
|
||||
}
|
||||
}
|
||||
|
||||
got = argSingle
|
||||
buf += string(r)
|
||||
if backQuote || dollarQuote {
|
||||
backtick += string(r)
|
||||
}
|
||||
}
|
||||
|
||||
if got != argNo {
|
||||
if p.ParseEnv {
|
||||
if got == argSingle {
|
||||
parser := &Parser{ParseEnv: false, ParseBacktick: false, Position: 0, Dir: p.Dir}
|
||||
strs, err := parser.Parse(replaceEnv(p.Getenv, buf))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args = append(args, strs...)
|
||||
} else {
|
||||
args = append(args, replaceEnv(p.Getenv, buf))
|
||||
}
|
||||
} else {
|
||||
args = append(args, buf)
|
||||
}
|
||||
}
|
||||
|
||||
if escaped || singleQuoted || doubleQuoted || backQuote || dollarQuote {
|
||||
return nil, errors.New("invalid command line string")
|
||||
}
|
||||
|
||||
p.Position = pos
|
||||
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (p *Parser) ParseWithEnvs(line string) (envs []string, args []string, err error) {
|
||||
_args, err := p.Parse(line)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
envs = []string{}
|
||||
args = []string{}
|
||||
parsingEnv := true
|
||||
for _, arg := range _args {
|
||||
if parsingEnv && isEnv(arg) {
|
||||
envs = append(envs, arg)
|
||||
} else {
|
||||
if parsingEnv {
|
||||
parsingEnv = false
|
||||
}
|
||||
args = append(args, arg)
|
||||
}
|
||||
}
|
||||
return envs, args, nil
|
||||
}
|
||||
|
||||
func isEnv(arg string) bool {
|
||||
return len(strings.Split(arg, "=")) == 2
|
||||
}
|
||||
|
||||
func Parse(line string) ([]string, error) {
|
||||
return NewParser().Parse(line)
|
||||
}
|
||||
|
||||
func ParseWithEnvs(line string) (envs []string, args []string, err error) {
|
||||
return NewParser().ParseWithEnvs(line)
|
||||
}
|
29
vendor/github.com/mattn/go-shellwords/util_posix.go
generated
vendored
Normal file
29
vendor/github.com/mattn/go-shellwords/util_posix.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
// +build !windows
|
||||
|
||||
package shellwords
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func shellRun(line, dir string) (string, error) {
|
||||
var shell string
|
||||
if shell = os.Getenv("SHELL"); shell == "" {
|
||||
shell = "/bin/sh"
|
||||
}
|
||||
cmd := exec.Command(shell, "-c", line)
|
||||
if dir != "" {
|
||||
cmd.Dir = dir
|
||||
}
|
||||
b, err := cmd.Output()
|
||||
if err != nil {
|
||||
if eerr, ok := err.(*exec.ExitError); ok {
|
||||
b = eerr.Stderr
|
||||
}
|
||||
return "", fmt.Errorf("%s: %w", string(b), err)
|
||||
}
|
||||
return strings.TrimSpace(string(b)), nil
|
||||
}
|
29
vendor/github.com/mattn/go-shellwords/util_windows.go
generated
vendored
Normal file
29
vendor/github.com/mattn/go-shellwords/util_windows.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
// +build windows
|
||||
|
||||
package shellwords
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func shellRun(line, dir string) (string, error) {
|
||||
var shell string
|
||||
if shell = os.Getenv("COMSPEC"); shell == "" {
|
||||
shell = "cmd"
|
||||
}
|
||||
cmd := exec.Command(shell, "/c", line)
|
||||
if dir != "" {
|
||||
cmd.Dir = dir
|
||||
}
|
||||
b, err := cmd.Output()
|
||||
if err != nil {
|
||||
if eerr, ok := err.(*exec.ExitError); ok {
|
||||
b = eerr.Stderr
|
||||
}
|
||||
return "", fmt.Errorf("%s: %w", string(b), err)
|
||||
}
|
||||
return strings.TrimSpace(string(b)), nil
|
||||
}
|
Reference in New Issue
Block a user