Goroutine without waitgroup or channel; risks resource leaks or race conditions
go func() {
1// SPDX-License-Identifier: MIT23package processor45import (6 "fmt"7 "os"8 "path/filepath"9 "regexp"10 "runtime"11 "strings"1213 "github.com/boyter/gocodewalker"14)1516// ProcessResult runs the same pipeline as Process but returns structured results17// instead of formatting to stdout. Useful for programmatic consumers like MCP servers.18func ProcessResult() ([]LanguageSummary, error) {19 ProcessConstants()20 processFlags()21 cleanVisitedPaths()2223 if len(DirFilePaths) == 0 {24 DirFilePaths = append(DirFilePaths, ".")25 }2627 filePaths := []string{}28 dirPaths := []string{}2930 for _, f := range DirFilePaths {31 fpath := filepath.Clean(f)3233 s, err := os.Stat(fpath)34 if err != nil {35 return nil, fmt.Errorf("file or directory could not be read: %s", fpath)36 }3738 if s.IsDir() {39 dirPaths = append(dirPaths, fpath)40 } else {41 filePaths = append(filePaths, fpath)42 }43 }4445 SortBy = strings.ToLower(SortBy)46 ctx := processorContext{remap: newRemapConfig(RemapAll, RemapUnknown)}4748 printDebugF("NumCPU: %d", runtime.NumCPU())49 printDebugF("SortBy: %s", SortBy)50 printDebugF("PathDenyList: %v", PathDenyList)5152 potentialFilesQueue := make(chan *gocodewalker.File, FileListQueueSize)53 fileListQueue := make(chan *FileJob, FileListQueueSize)54 fileSummaryJobQueue := make(chan *FileJob, FileSummaryJobQueueSize)5556 fileWalker := gocodewalker.NewParallelFileWalker(dirPaths, potentialFilesQueue)57 fileWalker.SetErrorHandler(func(e error) bool {58 printError(e.Error())59 return true60 })61 fileWalker.IgnoreGitIgnore = GitIgnore62 fileWalker.IgnoreIgnoreFile = Ignore63 fileWalker.IgnoreGitModules = GitModuleIgnore64 fileWalker.IncludeHidden = true65 fileWalker.ExcludeDirectory = PathDenyList66 fileWalker.SetConcurrency(DirectoryWalkerJobWorkers)6768 if !SccIgnore {69 fileWalker.CustomIgnore = []string{".sccignore"}70 }7172 var excludePathRegexes []*regexp.Regexp73 for _, exclude := range Exclude {74 regexpResult, err := regexp.Compile(exclude)75 if err == nil {76 fileWalker.ExcludeFilenameRegex = append(fileWalker.ExcludeFilenameRegex, regexpResult)77 fileWalker.ExcludeDirectoryRegex = append(fileWalker.ExcludeDirectoryRegex, regexpResult)78 excludePathRegexes = append(excludePathRegexes, regexpResult)79 } else {80 printError(err.Error())81 }82 }8384 go func() {85 err := fileWalker.Start()86 if err != nil {87 printError(err.Error())88 }89 }()9091 go func() {92 for _, f := range filePaths {93 fileInfo, err := os.Lstat(f)94 if err != nil {95 continue96 }9798 fileJob := newFileJob(f, f, fileInfo)99 if fileJob != nil {100 fileListQueue <- fileJob101 }102 }103104 for fi := range potentialFilesQueue {105 shouldExclude := false106 for _, re := range excludePathRegexes {107 if re.MatchString(fi.Location) {108 shouldExclude = true109 break110 }111 }112 if shouldExclude {113 continue114 }115116 fileInfo, err := os.Lstat(fi.Location)117 if err != nil {118 continue119 }120121 if !fileInfo.IsDir() {122 fileJob := newFileJob(fi.Location, fi.Filename, fileInfo)123 if fileJob != nil {124 fileListQueue <- fileJob125 }126 }127 }128 close(fileListQueue)129 }()130131 go ctx.fileProcessorWorker(fileListQueue, fileSummaryJobQueue)132133 language := aggregateLanguageSummary(fileSummaryJobQueue)134 language = sortLanguageSummary(language)135136 return language, nil137}
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.