From c86373d6c0b81eddee929d148985e9cf8cf66879 Mon Sep 17 00:00:00 2001 From: Jaz White Date: Tue, 7 Jul 2026 15:06:52 -0400 Subject: [PATCH 1/2] Concatenate filepattern alias contents once per alias GenerateAliases rebuilt the full concatenation of matched file contents (plus a []byte-to-string copy) for every flag key. On a repo with ~80MB of matched source and ~160 flags, peak allocation reached tens of GB and the process was OOM-killed. Hoist the concatenation to GenerateAliases and reuse it across flags. Co-Authored-By: Claude Fable 5 --- aliases/alias.go | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/aliases/alias.go b/aliases/alias.go index 6cd3b3f9e..6706daf80 100644 --- a/aliases/alias.go +++ b/aliases/alias.go @@ -31,13 +31,26 @@ func GenerateAliases(flags []string, aliases []options.Alias, dir string) (map[s return nil, err } + // Filepattern contents concatenated once per alias; rebuilding them for + // every flag key multiplies peak memory by the number of flags. + patternContents := make(map[int]string, len(aliases)) + ret := make(map[string][]string, len(flags)) for _, flag := range flags { for i, a := range aliases { if a.Name == "" { a.Name = strconv.Itoa(i) } - flagAliases, err := generateAlias(a, flag, dir, allFileContents) + if a.Type.Canonical() == options.FilePattern { + if _, ok := patternContents[i]; !ok { + contents, err := concatFilePatternContents(a, dir, allFileContents) + if err != nil { + return nil, err + } + patternContents[i] = contents + } + } + flagAliases, err := generateAlias(a, flag, dir, allFileContents, patternContents[i]) if err != nil { return nil, err } @@ -48,12 +61,12 @@ func GenerateAliases(flags []string, aliases []options.Alias, dir string) (map[s return ret, nil } -func generateAlias(a options.Alias, flag, dir string, allFileContents FileContentsMap) (ret []string, err error) { +func generateAlias(a options.Alias, flag, dir string, allFileContents FileContentsMap, patternContents string) (ret []string, err error) { switch a.Type.Canonical() { case options.Literal: ret = a.Flags[flag] case options.FilePattern: - ret, err = GenerateAliasesFromFilePattern(a, flag, dir, allFileContents) + ret = matchFilePatternAliases(a, flag, patternContents) case options.Command: ret, err = GenerateAliasesFromCommand(a, flag, dir) default: @@ -87,21 +100,33 @@ func GenerateNamingConventionAlias(a options.Alias, flag string) (alias string, } func GenerateAliasesFromFilePattern(a options.Alias, flag, dir string, allFileContents FileContentsMap) ([]string, error) { - ret := []string{} - // Concatenate the contents of all files into a single byte array to be matched by specified patterns - fileContents := []byte{} + fileContents, err := concatFilePatternContents(a, dir, allFileContents) + if err != nil { + return nil, err + } + return matchFilePatternAliases(a, flag, fileContents), nil +} + +// concatFilePatternContents concatenates the contents of all files matched by +// the alias paths into a single string to be matched by specified patterns +func concatFilePatternContents(a options.Alias, dir string, allFileContents FileContentsMap) (string, error) { + var sb strings.Builder for _, path := range a.Paths { matches, err := cacheFilepathGlob(dir, path) if err != nil { - return nil, fmt.Errorf("filepattern '%s': could not process path glob '%s'", a.Name, path) + return "", fmt.Errorf("filepattern '%s': could not process path glob '%s'", a.Name, path) } for _, match := range matches { if pathFileContents := allFileContents[match]; len(pathFileContents) > 0 { - fileContents = append(fileContents, pathFileContents...) + sb.Write(pathFileContents) } } } + return sb.String(), nil +} +func matchFilePatternAliases(a options.Alias, flag, fileContents string) []string { + ret := []string{} for _, p := range a.Patterns { patternStr := strings.ReplaceAll(p, "FLAG_KEY", flag) pattern, ok := regexCache[patternStr] @@ -109,15 +134,14 @@ func GenerateAliasesFromFilePattern(a options.Alias, flag, dir string, allFileCo pattern = regexp.MustCompile(patternStr) regexCache[patternStr] = pattern } - results := pattern.FindAllStringSubmatch(string(fileContents), -1) + results := pattern.FindAllStringSubmatch(fileContents, -1) for _, res := range results { if len(res) > 1 { ret = append(ret, res[1:]...) } } } - - return ret, nil + return ret } func GenerateAliasesFromCommand(a options.Alias, flag, dir string) ([]string, error) { From ef0bd5840622ba6a5463aaed99f325d6ff19be0f Mon Sep 17 00:00:00 2001 From: Jaz White Date: Wed, 15 Jul 2026 11:58:14 -0400 Subject: [PATCH 2/2] fix: drop unused allFileContents param from generateAlias Co-Authored-By: Claude Fable 5 --- aliases/alias.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aliases/alias.go b/aliases/alias.go index 6706daf80..b132901cb 100644 --- a/aliases/alias.go +++ b/aliases/alias.go @@ -50,7 +50,7 @@ func GenerateAliases(flags []string, aliases []options.Alias, dir string) (map[s patternContents[i] = contents } } - flagAliases, err := generateAlias(a, flag, dir, allFileContents, patternContents[i]) + flagAliases, err := generateAlias(a, flag, dir, patternContents[i]) if err != nil { return nil, err } @@ -61,7 +61,7 @@ func GenerateAliases(flags []string, aliases []options.Alias, dir string) (map[s return ret, nil } -func generateAlias(a options.Alias, flag, dir string, allFileContents FileContentsMap, patternContents string) (ret []string, err error) { +func generateAlias(a options.Alias, flag, dir string, patternContents string) (ret []string, err error) { switch a.Type.Canonical() { case options.Literal: ret = a.Flags[flag]