@@ -84,25 +84,12 @@ func (p *builtinServiceClient) Evaluate(ctx context.Context, cap string, conditi
8484 if c .Pattern == "" {
8585 return response , fmt .Errorf ("could not parse provided regex pattern as string: %v" , conditionInfo )
8686 }
87+
8788 var outputBytes []byte
88- var err error
89- if runtime .GOOS == "darwin" {
90- cmd := fmt .Sprintf (
91- `find %v -type f | \
92- while read file; do perl -ne '/(%v)/ && print "$ARGV:$.:$1\n";' "$file"; done` ,
93- p .config .Location , c .Pattern ,
94- )
95- findstr := exec .Command ("/bin/sh" , "-c" , cmd )
96- outputBytes , err = findstr .Output ()
97- } else {
98- grep := exec .Command ("grep" , "-o" , "-n" , "-R" , "-P" , c .Pattern , p .config .Location )
99- outputBytes , err = grep .Output ()
100- }
89+ //Runs on Windows using PowerShell.exe and Unix based systems using grep
90+ outputBytes , err := runOSSpecificGrepCommand (c .Pattern , p .config .Location , cond .ProviderContext )
10191 if err != nil {
102- if exitError , ok := err .(* exec.ExitError ); ok && exitError .ExitCode () == 1 {
103- return response , nil
104- }
105- return response , fmt .Errorf ("could not run grep with provided pattern %+v" , err )
92+ return response , err
10693 }
10794 matches := []string {}
10895 outputString := strings .TrimSpace (string (outputBytes ))
@@ -111,13 +98,10 @@ func (p *builtinServiceClient) Evaluate(ctx context.Context, cap string, conditi
11198 }
11299
113100 for _ , match := range matches {
114- //TODO(fabianvf): This will not work if there is a `:` in the filename, do we care?
115- pieces := strings .SplitN (match , ":" , 3 )
116- if len (pieces ) != 3 {
117- //TODO(fabianvf): Just log or return?
118- //(shawn-hurley): I think the return is good personally
119- return response , fmt .Errorf (
120- "malformed response from grep, cannot parse grep output '%s' with pattern {filepath}:{lineNumber}:{matchingText}" , match )
101+ var pieces []string
102+ pieces , err := parseGrepOutputForFileContent (match )
103+ if err != nil {
104+ return response , fmt .Errorf ("could not parse grep output '%s' for the Pattern '%v': %v " , match , c .Pattern , err )
121105 }
122106
123107 containsFile , err := provider .FilterFilePattern (c .FilePattern , pieces [0 ])
@@ -141,6 +125,7 @@ func (p *builtinServiceClient) Evaluate(ctx context.Context, cap string, conditi
141125 if err != nil {
142126 return response , fmt .Errorf ("cannot convert line number string to integer" )
143127 }
128+
144129 response .Incidents = append (response .Incidents , provider.IncidentContext {
145130 FileURI : uri .File (absPath ),
146131 LineNumber : & lineNumber ,
@@ -508,3 +493,66 @@ func (b *builtinServiceClient) isFileIncluded(absolutePath string) bool {
508493 b .log .V (7 ).Info ("excluding file from search" , "file" , absolutePath )
509494 return false
510495}
496+
497+ func parseGrepOutputForFileContent (match string ) ([]string , error ) {
498+ // This will parse the output of the PowerShell/grep in the form
499+ // "Filepath:Linenumber:Matchingtext" to return string array of path, line number and matching text
500+ // works with handling both windows and unix based file paths eg: "C:\path\to\file" and "/path/to/file"
501+ re , err := regexp .Compile (`^(.*?):(\d+):(.*)$` )
502+ if err != nil {
503+ return nil , fmt .Errorf ("failed to compile regular expression: %v" , err )
504+ }
505+ submatches := re .FindStringSubmatch (match )
506+ if len (submatches ) != 4 {
507+ return nil , fmt .Errorf (
508+ "malformed response from file search, cannot parse result '%s' with pattern %#q" , match , re )
509+ }
510+ return submatches [1 :], nil
511+ }
512+
513+ func runOSSpecificGrepCommand (pattern string , location string , providerContext provider.ProviderContext ) ([]byte , error ) {
514+ var outputBytes []byte
515+ var err error
516+ var utilName string
517+
518+ if runtime .GOOS == "windows" {
519+ utilName = "powershell.exe"
520+ // Windows does not have grep, so we use PowerShell.exe's Select-String instead
521+ // This is a workaround until we can find a better solution
522+ psScript := `
523+ $pattern = $env:PATTERN
524+ $location = $env:FILEPATH
525+ Get-ChildItem -Path $location -Recurse -File | ForEach-Object {
526+ $file = $_
527+ # Search for the pattern in the file
528+ Select-String -Path $file.FullName -Pattern $pattern -AllMatches | ForEach-Object {
529+ foreach ($match in $_.Matches) {
530+ "{0}:{1}:{2}" -f $file.FullName, $_.LineNumber, $match.Value
531+ }
532+ }
533+ }`
534+ findstr := exec .Command (utilName , "-Command" , psScript )
535+ findstr .Env = append (os .Environ (), "PATTERN=" + pattern , "FILEPATH=" + location )
536+ outputBytes , err = findstr .Output ()
537+
538+ } else if runtime .GOOS == "darwin" {
539+ cmd := fmt .Sprintf (
540+ `find %v -type f | \
541+ while read file; do perl -ne '/(%v)/ && print "$ARGV:$.:$1\n";' "$file"; done` ,
542+ location , pattern ,
543+ )
544+ findstr := exec .Command ("/bin/sh" , "-c" , cmd )
545+ outputBytes , err = findstr .Output ()
546+ } else {
547+ grep := exec .Command ("grep" , "-o" , "-n" , "-R" , "-P" , pattern )
548+ outputBytes , err = grep .Output ()
549+ }
550+ if err != nil {
551+ if exitError , ok := err .(* exec.ExitError ); ok && exitError .ExitCode () == 1 {
552+ return nil , nil
553+ }
554+ return nil , fmt .Errorf ("could not run '%s' with provided pattern %+v" , utilName , err )
555+ }
556+
557+ return outputBytes , nil
558+ }
0 commit comments