feat: kubesphere 4.0 (#6115)

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

---------

Signed-off-by: ci-bot <ci-bot@kubesphere.io>
Co-authored-by: ks-ci-bot <ks-ci-bot@example.com>
Co-authored-by: joyceliu <joyceliu@yunify.com>
This commit is contained in:
KubeSphere CI Bot
2024-09-06 11:05:52 +08:00
committed by GitHub
parent b5015ec7b9
commit 447a51f08b
8557 changed files with 546695 additions and 1146174 deletions

View File

@@ -28,7 +28,7 @@ const (
// If src != nil, ParseFile parses the source from src and the filename
// is only used when recording position information.
// The type of the argument for the src parameter must be string,
// []byte, or io.Reader.
// []byte, io.Reader, or FilePortion.
// If src == nil, ParseFile parses the file specified by filename.
func Parse(filename string, src interface{}, mode Mode) (f *File, err error) {
in, err := newScanner(filename, src, mode&RetainComments != 0)
@@ -771,8 +771,7 @@ func (p *parser) parseArgs() []Expr {
}
// primary = IDENT
// | INT | FLOAT
// | STRING
// | INT | FLOAT | STRING | BYTES
// | '[' ... // list literal or comprehension
// | '{' ... // dict literal or comprehension
// | '(' ... // tuple or parenthesized expression
@@ -782,7 +781,7 @@ func (p *parser) parsePrimary() Expr {
case IDENT:
return p.parseIdent()
case INT, FLOAT, STRING:
case INT, FLOAT, STRING, BYTES:
var val interface{}
tok := p.tok
switch tok {
@@ -794,7 +793,7 @@ func (p *parser) parsePrimary() Expr {
}
case FLOAT:
val = p.tokval.float
case STRING:
case STRING, BYTES:
val = p.tokval.string
}
raw := p.tokval.raw

View File

@@ -10,6 +10,8 @@ import (
"fmt"
"strconv"
"strings"
"unicode"
"unicode/utf8"
)
// unesc maps single-letter chars following \ to their actual values.
@@ -40,23 +42,21 @@ var esc = [256]byte{
'"': '"',
}
// notEsc is a list of characters that can follow a \ in a string value
// without having to escape the \. That is, since ( is in this list, we
// quote the Go string "foo\\(bar" as the Python literal "foo\(bar".
// This really does happen in BUILD files, especially in strings
// being used as shell arguments containing regular expressions.
const notEsc = " !#$%&()*+,-./:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~"
// unquote unquotes the quoted string, returning the actual
// string value, whether the original was triple-quoted, and
// an error describing invalid input.
func unquote(quoted string) (s string, triple bool, err error) {
// string value, whether the original was triple-quoted,
// whether it was a byte string, and an error describing invalid input.
func unquote(quoted string) (s string, triple, isByte bool, err error) {
// Check for raw prefix: means don't interpret the inner \.
raw := false
if strings.HasPrefix(quoted, "r") {
raw = true
quoted = quoted[1:]
}
// Check for bytes prefix.
if strings.HasPrefix(quoted, "b") {
isByte = true
quoted = quoted[1:]
}
if len(quoted) < 2 {
err = fmt.Errorf("string literal too short")
@@ -127,22 +127,25 @@ func unquote(quoted string) (s string, triple bool, err error) {
switch quoted[1] {
default:
// In Python, if \z (for some byte z) is not a known escape sequence
// then it appears as literal text in the string.
buf.WriteString(quoted[:2])
quoted = quoted[2:]
// In Starlark, like Go, a backslash must escape something.
// (Python still treats unnecessary backslashes literally,
// but since 3.6 has emitted a deprecation warning.)
err = fmt.Errorf("invalid escape sequence \\%c", quoted[1])
return
case '\n':
// Ignore the escape and the line break.
quoted = quoted[2:]
case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '\'', '"':
// One-char escape
// One-char escape.
// Escapes are allowed for both kinds of quotation
// mark, not just the kind in use.
buf.WriteByte(unesc[quoted[1]])
quoted = quoted[2:]
case '0', '1', '2', '3', '4', '5', '6', '7':
// Octal escape, up to 3 digits.
// Octal escape, up to 3 digits, \OOO.
n := int(quoted[1] - '0')
quoted = quoted[2:]
for i := 1; i < 3; i++ {
@@ -152,6 +155,10 @@ func unquote(quoted string) (s string, triple bool, err error) {
n = n*8 + int(quoted[0]-'0')
quoted = quoted[1:]
}
if !isByte && n > 127 {
err = fmt.Errorf(`non-ASCII octal escape \%o (use \u%04X for the UTF-8 encoding of U+%04X)`, n, n, n)
return
}
if n >= 256 {
// NOTE: Python silently discards the high bit,
// so that '\541' == '\141' == 'a'.
@@ -162,7 +169,7 @@ func unquote(quoted string) (s string, triple bool, err error) {
buf.WriteByte(byte(n))
case 'x':
// Hexadecimal escape, exactly 2 digits.
// Hexadecimal escape, exactly 2 digits, \xXX. [0-127]
if len(quoted) < 4 {
err = fmt.Errorf(`truncated escape sequence %s`, quoted)
return
@@ -172,8 +179,41 @@ func unquote(quoted string) (s string, triple bool, err error) {
err = fmt.Errorf(`invalid escape sequence %s`, quoted[:4])
return
}
if !isByte && n > 127 {
err = fmt.Errorf(`non-ASCII hex escape %s (use \u%04X for the UTF-8 encoding of U+%04X)`,
quoted[:4], n, n)
return
}
buf.WriteByte(byte(n))
quoted = quoted[4:]
case 'u', 'U':
// Unicode code point, 4 (\uXXXX) or 8 (\UXXXXXXXX) hex digits.
sz := 6
if quoted[1] == 'U' {
sz = 10
}
if len(quoted) < sz {
err = fmt.Errorf(`truncated escape sequence %s`, quoted)
return
}
n, err1 := strconv.ParseUint(quoted[2:sz], 16, 0)
if err1 != nil {
err = fmt.Errorf(`invalid escape sequence %s`, quoted[:sz])
return
}
if n > unicode.MaxRune {
err = fmt.Errorf(`code point out of range: %s (max \U%08x)`,
quoted[:sz], n)
return
}
// As in Go, surrogates are disallowed.
if 0xD800 <= n && n < 0xE000 {
err = fmt.Errorf(`invalid Unicode code point U+%04X`, n)
return
}
buf.WriteRune(rune(n))
quoted = quoted[sz:]
}
}
@@ -191,79 +231,79 @@ func indexByte(s string, b byte) int {
return -1
}
// hex is a list of the hexadecimal digits, for use in quoting.
// We always print lower-case hexadecimal.
const hex = "0123456789abcdef"
// Quote returns a Starlark literal that denotes s.
// If b, it returns a bytes literal.
func Quote(s string, b bool) string {
const hex = "0123456789abcdef"
var runeTmp [utf8.UTFMax]byte
// quote returns the quoted form of the string value "x".
// If triple is true, quote uses the triple-quoted form """x""".
func quote(unquoted string, triple bool) string {
q := `"`
if triple {
q = `"""`
buf := make([]byte, 0, 3*len(s)/2)
if b {
buf = append(buf, 'b')
}
buf := new(strings.Builder)
buf.WriteString(q)
for i := 0; i < len(unquoted); i++ {
c := unquoted[i]
if c == '"' && triple && (i+1 < len(unquoted) && unquoted[i+1] != '"' || i+2 < len(unquoted) && unquoted[i+2] != '"') {
// Can pass up to two quotes through, because they are followed by a non-quote byte.
buf.WriteByte(c)
if i+1 < len(unquoted) && unquoted[i+1] == '"' {
buf.WriteByte(c)
i++
}
buf = append(buf, '"')
for width := 0; len(s) > 0; s = s[width:] {
r := rune(s[0])
width = 1
if r >= utf8.RuneSelf {
r, width = utf8.DecodeRuneInString(s)
}
if width == 1 && r == utf8.RuneError {
// String (!b) literals accept \xXX escapes only for ASCII,
// but we must use them here to represent invalid bytes.
// The result is not a legal literal.
buf = append(buf, `\x`...)
buf = append(buf, hex[s[0]>>4])
buf = append(buf, hex[s[0]&0xF])
continue
}
if triple && c == '\n' {
// Can allow newline in triple-quoted string.
buf.WriteByte(c)
if r == '"' || r == '\\' { // always backslashed
buf = append(buf, '\\')
buf = append(buf, byte(r))
continue
}
if c == '\'' {
// Can allow ' since we always use ".
buf.WriteByte(c)
if strconv.IsPrint(r) {
n := utf8.EncodeRune(runeTmp[:], r)
buf = append(buf, runeTmp[:n]...)
continue
}
if c == '\\' {
if i+1 < len(unquoted) && indexByte(notEsc, unquoted[i+1]) >= 0 {
// Can pass \ through when followed by a byte that
// known not to be a valid escape sequence and also
// that does not trigger an escape sequence of its own.
// Use this, because various BUILD files do.
buf.WriteByte('\\')
buf.WriteByte(unquoted[i+1])
i++
continue
switch r {
case '\a':
buf = append(buf, `\a`...)
case '\b':
buf = append(buf, `\b`...)
case '\f':
buf = append(buf, `\f`...)
case '\n':
buf = append(buf, `\n`...)
case '\r':
buf = append(buf, `\r`...)
case '\t':
buf = append(buf, `\t`...)
case '\v':
buf = append(buf, `\v`...)
default:
switch {
case r < ' ' || r == 0x7f:
buf = append(buf, `\x`...)
buf = append(buf, hex[byte(r)>>4])
buf = append(buf, hex[byte(r)&0xF])
case r > utf8.MaxRune:
r = 0xFFFD
fallthrough
case r < 0x10000:
buf = append(buf, `\u`...)
for s := 12; s >= 0; s -= 4 {
buf = append(buf, hex[r>>uint(s)&0xF])
}
default:
buf = append(buf, `\U`...)
for s := 28; s >= 0; s -= 4 {
buf = append(buf, hex[r>>uint(s)&0xF])
}
}
}
if esc[c] != 0 {
buf.WriteByte('\\')
buf.WriteByte(esc[c])
continue
}
if c < 0x20 || c >= 0x80 {
// BUILD files are supposed to be Latin-1, so escape all control and high bytes.
// I'd prefer to use \x here, but Blaze does not implement
// \x in quoted strings (b/7272572).
buf.WriteByte('\\')
buf.WriteByte(hex[c>>6]) // actually octal but reusing hex digits 0-7.
buf.WriteByte(hex[(c>>3)&7])
buf.WriteByte(hex[c&7])
/*
buf.WriteByte('\\')
buf.WriteByte('x')
buf.WriteByte(hex[c>>4])
buf.WriteByte(hex[c&0xF])
*/
continue
}
buf.WriteByte(c)
continue
}
buf.WriteString(q)
return buf.String()
buf = append(buf, '"')
return string(buf)
}

View File

@@ -35,6 +35,7 @@ const (
INT // 123
FLOAT // 1.23e45
STRING // "foo" or 'foo' or '''foo''' or r'foo' or r"foo"
BYTES // b"foo", etc
// Punctuation
PLUS // +
@@ -182,6 +183,15 @@ var tokenNames = [...]string{
WHILE: "while",
}
// A FilePortion describes the content of a portion of a file.
// Callers may provide a FilePortion for the src argument of Parse
// when the desired initial line and column numbers are not (1, 1),
// such as when an expression is parsed from within larger file.
type FilePortion struct {
Content []byte
FirstLine, FirstCol int32
}
// A Position describes the location of a rune of input.
type Position struct {
file *string // filename (indirect for compactness)
@@ -249,13 +259,17 @@ type scanner struct {
}
func newScanner(filename string, src interface{}, keepComments bool) (*scanner, error) {
var firstLine, firstCol int32 = 1, 1
if portion, ok := src.(FilePortion); ok {
firstLine, firstCol = portion.FirstLine, portion.FirstCol
}
sc := &scanner{
pos: Position{file: &filename, Line: 1, Col: 1},
pos: MakePosition(&filename, firstLine, firstCol),
indentstk: make([]int, 1, 10), // []int{0} + spare capacity
lineStart: true,
keepComments: keepComments,
}
sc.readline, _ = src.(func() ([]byte, error)) // REPL only
sc.readline, _ = src.(func() ([]byte, error)) // ParseCompoundStmt (REPL) only
if sc.readline == nil {
data, err := readSource(filename, src)
if err != nil {
@@ -279,6 +293,8 @@ func readSource(filename string, src interface{}) ([]byte, error) {
return nil, err
}
return data, nil
case FilePortion:
return src.Content, nil
case nil:
return ioutil.ReadFile(filename)
default:
@@ -407,7 +423,7 @@ type tokenValue struct {
int int64 // decoded int
bigInt *big.Int // decoded integers > int64
float float64 // decoded float
string string // decoded string
string string // decoded string or bytes
pos Position // start position of token
}
@@ -627,8 +643,15 @@ start:
// identifier or keyword
if isIdentStart(c) {
// raw string literal
if c == 'r' && len(sc.rest) > 1 && (sc.rest[1] == '"' || sc.rest[1] == '\'') {
if (c == 'r' || c == 'b') && len(sc.rest) > 1 && (sc.rest[1] == '"' || sc.rest[1] == '\'') {
// r"..."
// b"..."
sc.readRune()
c = sc.peekRune()
return sc.scanString(val, c)
} else if c == 'r' && len(sc.rest) > 2 && sc.rest[1] == 'b' && (sc.rest[2] == '"' || sc.rest[2] == '\'') {
// rb"..."
sc.readRune()
sc.readRune()
c = sc.peekRune()
return sc.scanString(val, c)
@@ -805,13 +828,26 @@ func (sc *scanner) scanString(val *tokenValue, quote rune) Token {
start := sc.pos
triple := len(sc.rest) >= 3 && sc.rest[0] == byte(quote) && sc.rest[1] == byte(quote) && sc.rest[2] == byte(quote)
sc.readRune()
// String literals may contain escaped or unescaped newlines,
// causing them to span multiple lines (gulps) of REPL input;
// they are the only such token. Thus we cannot call endToken,
// as it assumes sc.rest is unchanged since startToken.
// Instead, buffer the token here.
// TODO(adonovan): opt: buffer only if we encounter a newline.
raw := new(strings.Builder)
// Copy the prefix, e.g. r' or " (see startToken).
raw.Write(sc.token[:len(sc.token)-len(sc.rest)])
if !triple {
// Precondition: startToken was already called.
// single-quoted string literal
for {
if sc.eof() {
sc.error(val.pos, "unexpected EOF in string")
}
c := sc.readRune()
raw.WriteRune(c)
if c == quote {
break
}
@@ -822,22 +858,16 @@ func (sc *scanner) scanString(val *tokenValue, quote rune) Token {
if sc.eof() {
sc.error(val.pos, "unexpected EOF in string")
}
sc.readRune()
c = sc.readRune()
raw.WriteRune(c)
}
}
sc.endToken(val)
} else {
// triple-quoted string literal
sc.readRune()
raw.WriteRune(quote)
sc.readRune()
// A triple-quoted string literal may span multiple
// gulps of REPL input; it is the only such token.
// Thus we must avoid {start,end}Token.
raw := new(strings.Builder)
// Copy the prefix, e.g. r''' or """ (see startToken).
raw.Write(sc.token[:len(sc.token)-len(sc.rest)])
raw.WriteRune(quote)
quoteCount := 0
for {
@@ -862,15 +892,19 @@ func (sc *scanner) scanString(val *tokenValue, quote rune) Token {
raw.WriteRune(c)
}
}
val.raw = raw.String()
}
val.raw = raw.String()
s, _, err := unquote(val.raw)
s, _, isByte, err := unquote(val.raw)
if err != nil {
sc.error(start, err.Error())
}
val.string = s
return STRING
if isByte {
return BYTES
} else {
return STRING
}
}
func (sc *scanner) scanNumber(val *tokenValue, c rune) Token {

View File

@@ -251,10 +251,10 @@ func (x *Ident) Span() (start, end Position) {
// A Literal represents a literal string or number.
type Literal struct {
commentsRef
Token Token // = STRING | INT
Token Token // = STRING | BYTES | INT | FLOAT
TokenPos Position
Raw string // uninterpreted text
Value interface{} // = string | int64 | *big.Int
Value interface{} // = string | int64 | *big.Int | float64
}
func (x *Literal) Span() (start, end Position) {
@@ -398,10 +398,6 @@ func (x *DictEntry) Span() (start, end Position) {
}
// A LambdaExpr represents an inline function abstraction.
//
// Although they may be added in future, lambda expressions are not
// currently part of the Starlark spec, so their use is controlled by the
// resolver.AllowLambda flag.
type LambdaExpr struct {
commentsRef
Lambda Position

View File

@@ -119,9 +119,7 @@ func Walk(n Node, f func(Node) bool) {
case *DictExpr:
for _, entry := range n.List {
entry := entry.(*DictEntry)
Walk(entry.Key, f)
Walk(entry.Value, f)
Walk(entry, f)
}
case *UnaryExpr: