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()22 cleanDuplicates()2324 if len(DirFilePaths) == 0 {25 DirFilePaths = append(DirFilePaths, ".")26 }2728 filePaths := []string{}29 dirPaths := []string{}3031 for _, f := range DirFilePaths {32 fpath := filepath.Clean(f)3334 s, err := os.Stat(fpath)35 if err != nil {36 return nil, fmt.Errorf("file or directory could not be read: %s", fpath)37 }3839 if s.IsDir() {40 dirPaths = append(dirPaths, fpath)41 } else {42 filePaths = append(filePaths, fpath)43 }44 }4546 SortBy = strings.ToLower(SortBy)47 ctx := processorContext{remap: newRemapConfig(RemapAll, RemapUnknown)}4849 printDebugF("NumCPU: %d", runtime.NumCPU())50 printDebugF("SortBy: %s", SortBy)51 printDebugF("PathDenyList: %v", PathDenyList)5253 potentialFilesQueue := make(chan *gocodewalker.File, FileListQueueSize)54 fileListQueue := make(chan *FileJob, FileListQueueSize)55 fileSummaryJobQueue := make(chan *FileJob, FileSummaryJobQueueSize)5657 fileWalker := gocodewalker.NewParallelFileWalker(dirPaths, potentialFilesQueue)58 fileWalker.SetErrorHandler(func(e error) bool {59 printError(e.Error())60 return true61 })62 fileWalker.IgnoreGitIgnore = GitIgnore63 fileWalker.IgnoreIgnoreFile = Ignore64 fileWalker.IgnoreGitModules = GitModuleIgnore65 fileWalker.IncludeHidden = true66 fileWalker.ExcludeDirectory = PathDenyList67 fileWalker.SetConcurrency(DirectoryWalkerJobWorkers)6869 if !SccIgnore {70 fileWalker.CustomIgnore = []string{".sccignore"}71 }72 fileWalker.CustomIgnoreFiles = IgnoreFiles7374 var excludePathRegexes []*regexp.Regexp75 for _, exclude := range Exclude {76 regexpResult, err := regexp.Compile(exclude)77 if err == nil {78 fileWalker.ExcludeFilenameRegex = append(fileWalker.ExcludeFilenameRegex, regexpResult)79 fileWalker.ExcludeDirectoryRegex = append(fileWalker.ExcludeDirectoryRegex, regexpResult)80 excludePathRegexes = append(excludePathRegexes, regexpResult)81 } else {82 printError(err.Error())83 }84 }8586 go func() {87 err := fileWalker.Start()88 if err != nil {89 printError(err.Error())90 }91 }()9293 go func() {94 for _, f := range filePaths {95 fileInfo, err := os.Lstat(f)96 if err != nil {97 continue98 }99100 fileJob := newFileJob(f, f, fileInfo)101 if fileJob != nil {102 fileListQueue <- fileJob103 }104 }105106 for fi := range potentialFilesQueue {107 shouldExclude := false108 for _, re := range excludePathRegexes {109 if re.MatchString(fi.Location) {110 shouldExclude = true111 break112 }113 }114 if shouldExclude {115 continue116 }117118 fileInfo, err := os.Lstat(fi.Location)119 if err != nil {120 continue121 }122123 if !fileInfo.IsDir() {124 fileJob := newFileJob(fi.Location, fi.Filename, fileInfo)125 if fileJob != nil {126 fileListQueue <- fileJob127 }128 }129 }130 close(fileListQueue)131 }()132133 go ctx.fileProcessorWorker(fileListQueue, fileSummaryJobQueue)134135 language := aggregateLanguageSummary(fileSummaryJobQueue)136 language = sortLanguageSummary(language)137138 return language, nil139}
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.