Skip to content

Instantly share code, notes, and snippets.

@chinmay185
Last active April 14, 2017 16:02
Show Gist options
  • Save chinmay185/0a188fffba38d4436836b567bb0b7ac8 to your computer and use it in GitHub Desktop.
Save chinmay185/0a188fffba38d4436836b567bb0b7ac8 to your computer and use it in GitHub Desktop.
basic simulation of grep command using multiple goroutines (for tests, see https://gist.github.com/chinmay185/15e0a81deee73571ce9b74d65d1da7eb)
package grep
import (
"bufio"
"flag"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"sync"
)
type FileProcessor interface {
Process(name string)
}
type Grepper struct {
results chan<- []string
wg *sync.WaitGroup
searchText string
}
func makeGrepper(results chan<- []string, wg *sync.WaitGroup, text string) *Grepper {
return &Grepper{results: results, wg: wg, searchText: text}
}
func (g Grepper) Process(name string) {
g.wg.Add(1)
go g.process(name)
}
func (g Grepper) process(name string) {
defer g.wg.Done()
file, err := os.Open(name)
defer file.Close()
if err != nil {
log.Printf("Error reading %s", name)
return
}
output := g.search(file, file.Name())
g.results <- output
}
func (g *Grepper) search(rd io.Reader, prefix string) []string {
scanner := bufio.NewScanner(rd)
buf := []string{}
for scanner.Scan() {
if strings.Contains(scanner.Text(), g.searchText) {
output := prefix + ":" + scanner.Text()
buf = append(buf, output)
}
}
if err := scanner.Err(); err != nil {
log.Fatal("scanner error ", err)
}
return buf
}
type Walker struct {
fType string
root string
}
func makeWalker(fileType, root string) *Walker {
return &Walker{fType: fileType, root: root}
}
func (w *Walker) Walk(fp FileProcessor) {
allFiles, err := ioutil.ReadDir(w.root)
if err != nil {
log.Println("Cannot read from dir: ", w.root)
return
}
for _, f := range allFiles {
if f.IsDir() {
makeWalker(w.fType, filepath.Join(w.root, f.Name())).Walk(fp)
} else if strings.HasSuffix(f.Name(), w.fType) {
fullFilePath := filepath.Join(w.root, f.Name())
fp.Process(fullFilePath)
}
}
}
func ParallelGrep() {
root := flag.String("dir", "", "directory where to search")
fileType := flag.String("type", "", "type of fileNames to search in")
searchText := flag.String("text", "", "text to search")
flag.Parse()
if *root == "" || *fileType == "" || *searchText == "" {
flag.PrintDefaults()
os.Exit(1)
}
results := make(chan []string)
var wg sync.WaitGroup
grepper := makeGrepper(results, &wg, *searchText)
w := makeWalker(*fileType, *root)
go func() {
for r := range results {
for _, line := range r {
log.Println(line)
}
}
}()
w.Walk(grepper)
wg.Wait()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment