refactor(executor): compile the hashFiles regexps once
The glob code compiled the same three regular expressions on every call. They are package variables now.
- commit
- 5a16c3defabaa5489ee367485fd39537b035b02e
- author
- brice · · 2026-10-13 04:04 UTC
- parent
- c9a800a
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +11 -5
M internal/executor/hashfiles.go +11 -5
| @@ -109,7 +109,7 @@ const ( | |||
| 109 | 109 | ) | |
| 110 | 110 | ||
| 111 | 111 | func splitSlash(s string) []string { | |
| 112 | - | return regexp.MustCompile(`/+`).Split(s, -1) | |
| 112 | + | return slashRunRe.Split(s, -1) | |
| 113 | 113 | } | |
| 114 | 114 | ||
| 115 | 115 | var errPattern = errors.New("invalid pattern") | |
| @@ -126,7 +126,7 @@ func newGlobPattern(text, cwd, home string) (*globPattern, error) { | |||
| 126 | 126 | if text == "" { | |
| 127 | 127 | return nil, fmt.Errorf("%w: pattern cannot be empty", errPattern) | |
| 128 | 128 | } | |
| 129 | - | norm := regexp.MustCompile(`//+`).ReplaceAllString(text, "/") | |
| 129 | + | norm := doubleSlashRe.ReplaceAllString(text, "/") | |
| 130 | 130 | p.trailingSep = strings.HasSuffix(norm, "/") | |
| 131 | 131 | trimmed := norm | |
| 132 | 132 | if trimmed != "/" { | |
| @@ -266,6 +266,12 @@ func getLiteral(s string) string { | |||
| 266 | 266 | return string(lit) | |
| 267 | 267 | } | |
| 268 | 268 | ||
| 269 | + | var ( | |
| 270 | + | slashRunRe = regexp.MustCompile(`/+`) | |
| 271 | + | doubleSlashRe = regexp.MustCompile(`//+`) | |
| 272 | + | neverMatchesRe = regexp.MustCompile(`$.`) | |
| 273 | + | ) | |
| 274 | + | ||
| 269 | 275 | const reSpecials = "().*{}+?[]^$\\!" | |
| 270 | 276 | ||
| 271 | 277 | // parseMM is minimatch's parse for one segment with the options of | |
| @@ -283,7 +289,7 @@ func parseMM(s string) mmSeg { | |||
| 283 | 289 | } | |
| 284 | 290 | rx, err := regexp.Compile("^" + re + "$") | |
| 285 | 291 | if err != nil { | |
| 286 | - | return mmSeg{re: regexp.MustCompile(`$.`)} | |
| 292 | + | return mmSeg{re: neverMatchesRe} | |
| 287 | 293 | } | |
| 288 | 294 | return mmSeg{re: rx} | |
| 289 | 295 | } | |
| @@ -395,7 +401,7 @@ func translateMM(p []rune) (re string, magic bool) { | |||
| 395 | 401 | // match is Pattern.match. | |
| 396 | 402 | func (p *globPattern) match(item string) int { | |
| 397 | 403 | if p.segs[len(p.segs)-1].raw == "**" { | |
| 398 | - | item = regexp.MustCompile(`//+`).ReplaceAllString(item, "/") | |
| 404 | + | item = doubleSlashRe.ReplaceAllString(item, "/") | |
| 399 | 405 | if !strings.HasSuffix(item, "/") && !p.implicit { | |
| 400 | 406 | item += "/" | |
| 401 | 407 | } | |
| @@ -429,7 +435,7 @@ func (p *globPattern) partialMatch(item string) bool { | |||
| 429 | 435 | } | |
| 430 | 436 | ||
| 431 | 437 | func trimTrailingSep(s string) string { | |
| 432 | - | s = regexp.MustCompile(`//+`).ReplaceAllString(s, "/") | |
| 438 | + | s = doubleSlashRe.ReplaceAllString(s, "/") | |
| 433 | 439 | if s != "/" && strings.HasSuffix(s, "/") { | |
| 434 | 440 | return s[:len(s)-1] | |
| 435 | 441 | } | |
| @@ -109,7 +109,7 @@ const ( | |||||
| 109 | ) | 109 | ) | ||
| 110 | 110 | ||||
| 111 | func splitSlash(s string) []string { | 111 | func splitSlash(s string) []string { | ||
| 112 | - | return regexp.MustCompile(`/+`).Split(s, -1) | 112 | + | return slashRunRe.Split(s, -1) |
| 113 | } | 113 | } | ||
| 114 | 114 | ||||
| 115 | var errPattern = errors.New("invalid pattern") | 115 | var errPattern = errors.New("invalid pattern") | ||
| @@ -126,7 +126,7 @@ func newGlobPattern(text, cwd, home string) (*globPattern, error) { | |||||
| 126 | if text == "" { | 126 | if text == "" { | ||
| 127 | return nil, fmt.Errorf("%w: pattern cannot be empty", errPattern) | 127 | return nil, fmt.Errorf("%w: pattern cannot be empty", errPattern) | ||
| 128 | } | 128 | } | ||
| 129 | - | norm := regexp.MustCompile(`//+`).ReplaceAllString(text, "/") | 129 | + | norm := doubleSlashRe.ReplaceAllString(text, "/") |
| 130 | p.trailingSep = strings.HasSuffix(norm, "/") | 130 | p.trailingSep = strings.HasSuffix(norm, "/") | ||
| 131 | trimmed := norm | 131 | trimmed := norm | ||
| 132 | if trimmed != "/" { | 132 | if trimmed != "/" { | ||
| @@ -266,6 +266,12 @@ func getLiteral(s string) string { | |||||
| 266 | return string(lit) | 266 | return string(lit) | ||
| 267 | } | 267 | } | ||
| 268 | 268 | ||||
| 269 | + | var ( | |||
| 270 | + | slashRunRe = regexp.MustCompile(`/+`) | |||
| 271 | + | doubleSlashRe = regexp.MustCompile(`//+`) | |||
| 272 | + | neverMatchesRe = regexp.MustCompile(`$.`) | |||
| 273 | + | ) | |||
| 274 | + | ||||
| 269 | const reSpecials = "().*{}+?[]^$\\!" | 275 | const reSpecials = "().*{}+?[]^$\\!" | ||
| 270 | 276 | ||||
| 271 | // parseMM is minimatch's parse for one segment with the options of | 277 | // parseMM is minimatch's parse for one segment with the options of | ||
| @@ -283,7 +289,7 @@ func parseMM(s string) mmSeg { | |||||
| 283 | } | 289 | } | ||
| 284 | rx, err := regexp.Compile("^" + re + "$") | 290 | rx, err := regexp.Compile("^" + re + "$") | ||
| 285 | if err != nil { | 291 | if err != nil { | ||
| 286 | - | return mmSeg{re: regexp.MustCompile(`$.`)} | 292 | + | return mmSeg{re: neverMatchesRe} |
| 287 | } | 293 | } | ||
| 288 | return mmSeg{re: rx} | 294 | return mmSeg{re: rx} | ||
| 289 | } | 295 | } | ||
| @@ -395,7 +401,7 @@ func translateMM(p []rune) (re string, magic bool) { | |||||
| 395 | // match is Pattern.match. | 401 | // match is Pattern.match. | ||
| 396 | func (p *globPattern) match(item string) int { | 402 | func (p *globPattern) match(item string) int { | ||
| 397 | if p.segs[len(p.segs)-1].raw == "**" { | 403 | if p.segs[len(p.segs)-1].raw == "**" { | ||
| 398 | - | item = regexp.MustCompile(`//+`).ReplaceAllString(item, "/") | 404 | + | item = doubleSlashRe.ReplaceAllString(item, "/") |
| 399 | if !strings.HasSuffix(item, "/") && !p.implicit { | 405 | if !strings.HasSuffix(item, "/") && !p.implicit { | ||
| 400 | item += "/" | 406 | item += "/" | ||
| 401 | } | 407 | } | ||
| @@ -429,7 +435,7 @@ func (p *globPattern) partialMatch(item string) bool { | |||||
| 429 | } | 435 | } | ||
| 430 | 436 | ||||
| 431 | func trimTrailingSep(s string) string { | 437 | func trimTrailingSep(s string) string { | ||
| 432 | - | s = regexp.MustCompile(`//+`).ReplaceAllString(s, "/") | 438 | + | s = doubleSlashRe.ReplaceAllString(s, "/") |
| 433 | if s != "/" && strings.HasSuffix(s, "/") { | 439 | if s != "/" && strings.HasSuffix(s, "/") { | ||
| 434 | return s[:len(s)-1] | 440 | return s[:len(s)-1] | ||
| 435 | } | 441 | } | ||