github.com/scottcagno/storage@v1.8.0/pkg/filesystem/grep.go (about)

     1  package filesystem
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  	"path/filepath"
     9  	"regexp"
    10  )
    11  
    12  func GrepWriter(w io.Writer, pattern string, path string) {
    13  	grep(w, pattern, path)
    14  }
    15  
    16  func Grep(pattern string, path string) {
    17  	grep(os.Stdout, pattern, path)
    18  }
    19  
    20  func grep(w io.Writer, pattern string, path string) {
    21  	// "error check"
    22  	if w == nil {
    23  		w = os.Stdout
    24  	}
    25  	// compile regex pattern
    26  	reg, err := regexp.Compile(pattern)
    27  	if err != nil {
    28  		return
    29  	}
    30  	// "clean" path
    31  	dir, file := filepath.Split(filepath.ToSlash(path))
    32  	// start walking
    33  	err = filepath.Walk(dir,
    34  		func(lpath string, info os.FileInfo, err error) error {
    35  			// clean local path
    36  			lpath = filepath.ToSlash(lpath)
    37  			// handle path error
    38  			if err != nil {
    39  				fmt.Fprintf(os.Stderr, "prevent panic by handling failure accessing a path %q: %v\n", lpath, err)
    40  				return err
    41  			}
    42  			// check for local file path match
    43  			fileMatches, _ := filepath.Match(file, lpath)
    44  			if !info.IsDir() && fileMatches {
    45  				// do search
    46  				err = search(w, lpath, reg)
    47  				if err != nil {
    48  					return err
    49  				}
    50  			}
    51  			return nil
    52  		})
    53  	// check for errors
    54  	if err != nil {
    55  		fmt.Fprintf(os.Stderr, "walk: %T, %+v, %s", err, err, err)
    56  	}
    57  }
    58  
    59  func search(w io.Writer, path string, reg *regexp.Regexp) error {
    60  	// open file
    61  	fd, err := os.Open(path)
    62  	if err != nil {
    63  		return err
    64  	}
    65  	// get scanner and start scanning
    66  	sc, ln := bufio.NewScanner(fd), 1
    67  	for sc.Scan() {
    68  		// check for match in file
    69  		foundMatch := reg.Match(sc.Bytes())
    70  		if foundMatch {
    71  			fmt.Fprintf(w, "\r%s:%d:%s\n", fd.Name(), ln, sc.Bytes())
    72  			//break
    73  		}
    74  		ln++
    75  	}
    76  	// close file
    77  	err = fd.Close()
    78  	if err != nil {
    79  		return err
    80  	}
    81  	// check scan errors
    82  	if err := sc.Err(); err != nil {
    83  		fmt.Fprintf(os.Stderr, "scanner: %T %s\n", err, err)
    84  		return err
    85  	}
    86  	return nil
    87  }