1
0
Fork 0
forked from forgejo/forgejo

Implement webhook branch filter (#7791)

* Fix validate() function to handle errors in embedded anon structs

* Implement webhook branch filter

See #2025, #3998.
This commit is contained in:
WGH 2019-09-09 08:48:21 +03:00 committed by Lauris BH
parent 0118b6aaf8
commit 6ddd3b0b47
52 changed files with 3168 additions and 19 deletions

122
vendor/github.com/gobwas/glob/syntax/ast/ast.go generated vendored Normal file
View file

@ -0,0 +1,122 @@
package ast
import (
"bytes"
"fmt"
)
type Node struct {
Parent *Node
Children []*Node
Value interface{}
Kind Kind
}
func NewNode(k Kind, v interface{}, ch ...*Node) *Node {
n := &Node{
Kind: k,
Value: v,
}
for _, c := range ch {
Insert(n, c)
}
return n
}
func (a *Node) Equal(b *Node) bool {
if a.Kind != b.Kind {
return false
}
if a.Value != b.Value {
return false
}
if len(a.Children) != len(b.Children) {
return false
}
for i, c := range a.Children {
if !c.Equal(b.Children[i]) {
return false
}
}
return true
}
func (a *Node) String() string {
var buf bytes.Buffer
buf.WriteString(a.Kind.String())
if a.Value != nil {
buf.WriteString(" =")
buf.WriteString(fmt.Sprintf("%v", a.Value))
}
if len(a.Children) > 0 {
buf.WriteString(" [")
for i, c := range a.Children {
if i > 0 {
buf.WriteString(", ")
}
buf.WriteString(c.String())
}
buf.WriteString("]")
}
return buf.String()
}
func Insert(parent *Node, children ...*Node) {
parent.Children = append(parent.Children, children...)
for _, ch := range children {
ch.Parent = parent
}
}
type List struct {
Not bool
Chars string
}
type Range struct {
Not bool
Lo, Hi rune
}
type Text struct {
Text string
}
type Kind int
const (
KindNothing Kind = iota
KindPattern
KindList
KindRange
KindText
KindAny
KindSuper
KindSingle
KindAnyOf
)
func (k Kind) String() string {
switch k {
case KindNothing:
return "Nothing"
case KindPattern:
return "Pattern"
case KindList:
return "List"
case KindRange:
return "Range"
case KindText:
return "Text"
case KindAny:
return "Any"
case KindSuper:
return "Super"
case KindSingle:
return "Single"
case KindAnyOf:
return "AnyOf"
default:
return ""
}
}

157
vendor/github.com/gobwas/glob/syntax/ast/parser.go generated vendored Normal file
View file

@ -0,0 +1,157 @@
package ast
import (
"errors"
"fmt"
"github.com/gobwas/glob/syntax/lexer"
"unicode/utf8"
)
type Lexer interface {
Next() lexer.Token
}
type parseFn func(*Node, Lexer) (parseFn, *Node, error)
func Parse(lexer Lexer) (*Node, error) {
var parser parseFn
root := NewNode(KindPattern, nil)
var (
tree *Node
err error
)
for parser, tree = parserMain, root; parser != nil; {
parser, tree, err = parser(tree, lexer)
if err != nil {
return nil, err
}
}
return root, nil
}
func parserMain(tree *Node, lex Lexer) (parseFn, *Node, error) {
for {
token := lex.Next()
switch token.Type {
case lexer.EOF:
return nil, tree, nil
case lexer.Error:
return nil, tree, errors.New(token.Raw)
case lexer.Text:
Insert(tree, NewNode(KindText, Text{token.Raw}))
return parserMain, tree, nil
case lexer.Any:
Insert(tree, NewNode(KindAny, nil))
return parserMain, tree, nil
case lexer.Super:
Insert(tree, NewNode(KindSuper, nil))
return parserMain, tree, nil
case lexer.Single:
Insert(tree, NewNode(KindSingle, nil))
return parserMain, tree, nil
case lexer.RangeOpen:
return parserRange, tree, nil
case lexer.TermsOpen:
a := NewNode(KindAnyOf, nil)
Insert(tree, a)
p := NewNode(KindPattern, nil)
Insert(a, p)
return parserMain, p, nil
case lexer.Separator:
p := NewNode(KindPattern, nil)
Insert(tree.Parent, p)
return parserMain, p, nil
case lexer.TermsClose:
return parserMain, tree.Parent.Parent, nil
default:
return nil, tree, fmt.Errorf("unexpected token: %s", token)
}
}
return nil, tree, fmt.Errorf("unknown error")
}
func parserRange(tree *Node, lex Lexer) (parseFn, *Node, error) {
var (
not bool
lo rune
hi rune
chars string
)
for {
token := lex.Next()
switch token.Type {
case lexer.EOF:
return nil, tree, errors.New("unexpected end")
case lexer.Error:
return nil, tree, errors.New(token.Raw)
case lexer.Not:
not = true
case lexer.RangeLo:
r, w := utf8.DecodeRuneInString(token.Raw)
if len(token.Raw) > w {
return nil, tree, fmt.Errorf("unexpected length of lo character")
}
lo = r
case lexer.RangeBetween:
//
case lexer.RangeHi:
r, w := utf8.DecodeRuneInString(token.Raw)
if len(token.Raw) > w {
return nil, tree, fmt.Errorf("unexpected length of lo character")
}
hi = r
if hi < lo {
return nil, tree, fmt.Errorf("hi character '%s' should be greater than lo '%s'", string(hi), string(lo))
}
case lexer.Text:
chars = token.Raw
case lexer.RangeClose:
isRange := lo != 0 && hi != 0
isChars := chars != ""
if isChars == isRange {
return nil, tree, fmt.Errorf("could not parse range")
}
if isRange {
Insert(tree, NewNode(KindRange, Range{
Lo: lo,
Hi: hi,
Not: not,
}))
} else {
Insert(tree, NewNode(KindList, List{
Chars: chars,
Not: not,
}))
}
return parserMain, tree, nil
}
}
}

273
vendor/github.com/gobwas/glob/syntax/lexer/lexer.go generated vendored Normal file
View file

@ -0,0 +1,273 @@
package lexer
import (
"bytes"
"fmt"
"github.com/gobwas/glob/util/runes"
"unicode/utf8"
)
const (
char_any = '*'
char_comma = ','
char_single = '?'
char_escape = '\\'
char_range_open = '['
char_range_close = ']'
char_terms_open = '{'
char_terms_close = '}'
char_range_not = '!'
char_range_between = '-'
)
var specials = []byte{
char_any,
char_single,
char_escape,
char_range_open,
char_range_close,
char_terms_open,
char_terms_close,
}
func Special(c byte) bool {
return bytes.IndexByte(specials, c) != -1
}
type tokens []Token
func (i *tokens) shift() (ret Token) {
ret = (*i)[0]
copy(*i, (*i)[1:])
*i = (*i)[:len(*i)-1]
return
}
func (i *tokens) push(v Token) {
*i = append(*i, v)
}
func (i *tokens) empty() bool {
return len(*i) == 0
}
var eof rune = 0
type lexer struct {
data string
pos int
err error
tokens tokens
termsLevel int
lastRune rune
lastRuneSize int
hasRune bool
}
func NewLexer(source string) *lexer {
l := &lexer{
data: source,
tokens: tokens(make([]Token, 0, 4)),
}
return l
}
func (l *lexer) Next() Token {
if l.err != nil {
return Token{Error, l.err.Error()}
}
if !l.tokens.empty() {
return l.tokens.shift()
}
l.fetchItem()
return l.Next()
}
func (l *lexer) peek() (r rune, w int) {
if l.pos == len(l.data) {
return eof, 0
}
r, w = utf8.DecodeRuneInString(l.data[l.pos:])
if r == utf8.RuneError {
l.errorf("could not read rune")
r = eof
w = 0
}
return
}
func (l *lexer) read() rune {
if l.hasRune {
l.hasRune = false
l.seek(l.lastRuneSize)
return l.lastRune
}
r, s := l.peek()
l.seek(s)
l.lastRune = r
l.lastRuneSize = s
return r
}
func (l *lexer) seek(w int) {
l.pos += w
}
func (l *lexer) unread() {
if l.hasRune {
l.errorf("could not unread rune")
return
}
l.seek(-l.lastRuneSize)
l.hasRune = true
}
func (l *lexer) errorf(f string, v ...interface{}) {
l.err = fmt.Errorf(f, v...)
}
func (l *lexer) inTerms() bool {
return l.termsLevel > 0
}
func (l *lexer) termsEnter() {
l.termsLevel++
}
func (l *lexer) termsLeave() {
l.termsLevel--
}
var inTextBreakers = []rune{char_single, char_any, char_range_open, char_terms_open}
var inTermsBreakers = append(inTextBreakers, char_terms_close, char_comma)
func (l *lexer) fetchItem() {
r := l.read()
switch {
case r == eof:
l.tokens.push(Token{EOF, ""})
case r == char_terms_open:
l.termsEnter()
l.tokens.push(Token{TermsOpen, string(r)})
case r == char_comma && l.inTerms():
l.tokens.push(Token{Separator, string(r)})
case r == char_terms_close && l.inTerms():
l.tokens.push(Token{TermsClose, string(r)})
l.termsLeave()
case r == char_range_open:
l.tokens.push(Token{RangeOpen, string(r)})
l.fetchRange()
case r == char_single:
l.tokens.push(Token{Single, string(r)})
case r == char_any:
if l.read() == char_any {
l.tokens.push(Token{Super, string(r) + string(r)})
} else {
l.unread()
l.tokens.push(Token{Any, string(r)})
}
default:
l.unread()
var breakers []rune
if l.inTerms() {
breakers = inTermsBreakers
} else {
breakers = inTextBreakers
}
l.fetchText(breakers)
}
}
func (l *lexer) fetchRange() {
var wantHi bool
var wantClose bool
var seenNot bool
for {
r := l.read()
if r == eof {
l.errorf("unexpected end of input")
return
}
if wantClose {
if r != char_range_close {
l.errorf("expected close range character")
} else {
l.tokens.push(Token{RangeClose, string(r)})
}
return
}
if wantHi {
l.tokens.push(Token{RangeHi, string(r)})
wantClose = true
continue
}
if !seenNot && r == char_range_not {
l.tokens.push(Token{Not, string(r)})
seenNot = true
continue
}
if n, w := l.peek(); n == char_range_between {
l.seek(w)
l.tokens.push(Token{RangeLo, string(r)})
l.tokens.push(Token{RangeBetween, string(n)})
wantHi = true
continue
}
l.unread() // unread first peek and fetch as text
l.fetchText([]rune{char_range_close})
wantClose = true
}
}
func (l *lexer) fetchText(breakers []rune) {
var data []rune
var escaped bool
reading:
for {
r := l.read()
if r == eof {
break
}
if !escaped {
if r == char_escape {
escaped = true
continue
}
if runes.IndexRune(breakers, r) != -1 {
l.unread()
break reading
}
}
escaped = false
data = append(data, r)
}
if len(data) > 0 {
l.tokens.push(Token{Text, string(data)})
}
}

88
vendor/github.com/gobwas/glob/syntax/lexer/token.go generated vendored Normal file
View file

@ -0,0 +1,88 @@
package lexer
import "fmt"
type TokenType int
const (
EOF TokenType = iota
Error
Text
Char
Any
Super
Single
Not
Separator
RangeOpen
RangeClose
RangeLo
RangeHi
RangeBetween
TermsOpen
TermsClose
)
func (tt TokenType) String() string {
switch tt {
case EOF:
return "eof"
case Error:
return "error"
case Text:
return "text"
case Char:
return "char"
case Any:
return "any"
case Super:
return "super"
case Single:
return "single"
case Not:
return "not"
case Separator:
return "separator"
case RangeOpen:
return "range_open"
case RangeClose:
return "range_close"
case RangeLo:
return "range_lo"
case RangeHi:
return "range_hi"
case RangeBetween:
return "range_between"
case TermsOpen:
return "terms_open"
case TermsClose:
return "terms_close"
default:
return "undef"
}
}
type Token struct {
Type TokenType
Raw string
}
func (t Token) String() string {
return fmt.Sprintf("%v<%q>", t.Type, t.Raw)
}

14
vendor/github.com/gobwas/glob/syntax/syntax.go generated vendored Normal file
View file

@ -0,0 +1,14 @@
package syntax
import (
"github.com/gobwas/glob/syntax/ast"
"github.com/gobwas/glob/syntax/lexer"
)
func Parse(s string) (*ast.Node, error) {
return ast.Parse(lexer.NewLexer(s))
}
func Special(b byte) bool {
return lexer.Special(b)
}