Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions assets/go-licenses.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cmd/embedded.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ import (
"strings"

"code.gitea.io/gitea/modules/assetfs"
"code.gitea.io/gitea/modules/glob"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/options"
"code.gitea.io/gitea/modules/public"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/util"

"github.com/gobwas/glob"
"github.com/urfave/cli/v3"
)

Expand Down
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ require (
github.com/go-redsync/redsync/v4 v4.13.0
github.com/go-sql-driver/mysql v1.9.3
github.com/go-webauthn/webauthn v0.13.4
github.com/gobwas/glob v0.2.3
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
github.com/golang-jwt/jwt/v5 v5.3.0
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,6 @@ github.com/go-webauthn/webauthn v0.13.4 h1:q68qusWPcqHbg9STSxBLBHnsKaLxNO0RnVKaA
github.com/go-webauthn/webauthn v0.13.4/go.mod h1:MglN6OH9ECxvhDqoq1wMoF6P6JRYDiQpC9nc5OomQmI=
github.com/go-webauthn/x v0.1.24 h1:6LaWf2zzWqbyKT8IyQkhje1/1KCGhlEkMz4V1tDnt/A=
github.com/go-webauthn/x v0.1.24/go.mod h1:2o5XKJ+X1AKqYKGgHdKflGnoQFQZ6flJ2IFCBKSbSOw=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
Expand Down
5 changes: 2 additions & 3 deletions models/git/protected_branch.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/glob"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"

"github.com/gobwas/glob"
"github.com/gobwas/glob/syntax"
"xorm.io/builder"
)

Expand Down Expand Up @@ -77,7 +76,7 @@ func init() {
// IsRuleNameSpecial return true if it contains special character
func IsRuleNameSpecial(ruleName string) bool {
for i := 0; i < len(ruleName); i++ {
if syntax.Special(ruleName[i]) {
if glob.IsSpecialByte(ruleName[i]) {
return true
}
}
Expand Down
3 changes: 1 addition & 2 deletions models/git/protected_branch_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ import (
"sort"

"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/glob"
"code.gitea.io/gitea/modules/optional"

"github.com/gobwas/glob"
)

type ProtectedBranchRules []*ProtectedBranch
Expand Down
3 changes: 1 addition & 2 deletions models/git/protected_tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ import (

"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/modules/glob"
"code.gitea.io/gitea/modules/timeutil"

"github.com/gobwas/glob"
)

// ProtectedTag struct
Expand Down
2 changes: 1 addition & 1 deletion modules/actions/workflows.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import (
"strings"

"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/glob"
"code.gitea.io/gitea/modules/log"
api "code.gitea.io/gitea/modules/structs"
webhook_module "code.gitea.io/gitea/modules/webhook"

"github.com/gobwas/glob"
"github.com/nektos/act/pkg/jobparser"
"github.com/nektos/act/pkg/model"
"github.com/nektos/act/pkg/workflowpattern"
Expand Down
184 changes: 184 additions & 0 deletions modules/glob/glob.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package glob

import (
"errors"
"fmt"
"regexp"

"code.gitea.io/gitea/modules/util"
)

// Reference: https://github.com/gobwas/glob/blob/master/glob.go

type Glob interface {
Match(string) bool
}

type globCompiler struct {
nonSeparatorChars string
globPattern []rune
regexpPattern string
regexp *regexp.Regexp
pos int
}

// compileChars compiles character class patterns like [abc] or [!abc]
func (g *globCompiler) compileChars() (string, error) {
result := ""
if g.pos < len(g.globPattern) && g.globPattern[g.pos] == '!' {
g.pos++
result += "^"
}

for g.pos < len(g.globPattern) {
c := g.globPattern[g.pos]
g.pos++

if c == ']' {
return "[" + result + "]", nil
}

if c == '\\' {
if g.pos >= len(g.globPattern) {
return "", errors.New("unterminated character class escape")
}
result += "\\" + string(g.globPattern[g.pos])
g.pos++
} else {
result += string(c)
}
}

return "", errors.New("unterminated character class")
}

// compile compiles the glob pattern into a regular expression
func (g *globCompiler) compile(subPattern bool) (string, error) {
result := ""

for g.pos < len(g.globPattern) {
c := g.globPattern[g.pos]
g.pos++

if subPattern && c == '}' {
return "(" + result + ")", nil
}

switch c {
case '*':
if g.pos < len(g.globPattern) && g.globPattern[g.pos] == '*' {
g.pos++
result += ".*" // match any sequence of characters
} else {
result += g.nonSeparatorChars + "*" // match any sequence of non-separator characters
}
case '?':
result += g.nonSeparatorChars // match any single non-separator character
case '[':
chars, err := g.compileChars()
if err != nil {
return "", err
}
result += chars
case '{':
subResult, err := g.compile(true)
if err != nil {
return "", err
}
result += subResult
case ',':
if subPattern {
result += "|"
} else {
result += ","
}
case '\\':
if g.pos >= len(g.globPattern) {
return "", errors.New("no character to escape")
}
result += "\\" + string(g.globPattern[g.pos])
g.pos++
case '.', '+', '^', '$', '(', ')', '|':
result += "\\" + string(c) // escape regexp special characters
default:
result += string(c)
}
}

return result, nil
}

func newGlobCompiler(pattern string, separators ...rune) (Glob, error) {
g := &globCompiler{globPattern: []rune(pattern)}

// Escape separators for use in character class
escapedSeparators := regexp.QuoteMeta(string(separators))
if escapedSeparators != "" {
g.nonSeparatorChars = "[^" + escapedSeparators + "]"
} else {
g.nonSeparatorChars = "."
}

compiled, err := g.compile(false)
if err != nil {
return nil, err
}

g.regexpPattern = "^" + compiled + "$"

regex, err := regexp.Compile(g.regexpPattern)
if err != nil {
return nil, fmt.Errorf("failed to compile regexp: %w", err)
}

g.regexp = regex
return g, nil
}

func (g *globCompiler) Match(s string) bool {
return g.regexp.MatchString(s)
}

func Compile(pattern string, separators ...rune) (Glob, error) {
return newGlobCompiler(pattern, separators...)
}

func MustCompile(pattern string, separators ...rune) Glob {
g, err := Compile(pattern, separators...)
if err != nil {
panic(err)
}
return g
}

func IsSpecialByte(c byte) bool {
return c == '*' || c == '?' || c == '\\' || c == '[' || c == ']' || c == '{' || c == '}'
}

// QuoteMeta returns a string that quotes all glob pattern meta characters
// inside the argument text; For example, QuoteMeta(`{foo*}`) returns `\[foo\*\]`.
// Reference: https://github.com/gobwas/glob/blob/master/glob.go
func QuoteMeta(s string) string {
pos := 0
for pos < len(s) && !IsSpecialByte(s[pos]) {
pos++
}
if pos == len(s) {
return s
}
b := make([]byte, pos+2*(len(s)-pos))
copy(b, s[0:pos])
to := pos
for ; pos < len(s); pos++ {
if IsSpecialByte(s[pos]) {
b[to] = '\\'
to++
}
b[to] = s[pos]
to++
}
return util.UnsafeBytesToString(b[0:to])
}
Loading