Skip to content

Instantly share code, notes, and snippets.

@rudenoise
Created September 1, 2012 19:52
Show Gist options
  • Save rudenoise/3585327 to your computer and use it in GitHub Desktop.
Save rudenoise/3585327 to your computer and use it in GitHub Desktop.
A Go program for counting lines in files under a given directory, makes use of parallelism via GoRoutines
package main
import (
"bufio"
"flag"
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"sort"
"sync"
)
var exclude = flag.String("exclude", "^$", "regexp pattern to exclude in file path")
var include = flag.String("include", "", "regexp pattern to include file path")
type File struct {
FilePath string
LineCount int
}
type Files []File
func (f Files) Len() int { return len(f) }
func (f Files) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
func (f Files) Less(i, j int) bool { return f[i].LineCount < f[j].LineCount }
type ByLengthReverse struct{ Files }
func (f ByLengthReverse) Less(i, j int) bool {
return f.Files[i].LineCount > f.Files[j].LineCount
}
func Paths(path string) []string {
paths := make([]string, 0)
err := filepath.Walk(path, func(cPath string, f os.FileInfo, err error) error {
if err != nil {
panic(err)
}
excludeMatch, err := regexp.MatchString(*exclude, cPath)
if err != nil {
panic(err)
}
includeMatch, err := regexp.MatchString(*include, cPath)
if err != nil {
panic(err)
}
if f.IsDir() == false && excludeMatch == false && includeMatch {
paths = append(paths, cPath)
}
return err
})
if err != nil {
panic(err)
}
return paths
}
func CountLines(filePath string) int {
count := 0
contents, err := os.Open(filePath)
defer contents.Close()
if err != nil {
panic(err)
}
buf := bufio.NewReader(contents)
for {
read, err := buf.ReadString('\n')
if err == io.EOF {
break
}
if err != nil {
panic(err)
}
if read != "" {
count++
}
}
return count
}
func OpenParallel(paths []string) Files {
var files Files
var wg sync.WaitGroup
for i := 0; i < len(paths); i++ {
wg.Add(1)
go func(fp string) {
lines := CountLines(fp)
files = append(files, File{fp, lines})
wg.Done()
}(paths[i])
}
wg.Wait()
return files
}
func main() {
flag.Parse()
dir := filepath.Dir(flag.Arg(0))
pths := Paths(dir)
limit := 5000
if len(pths) < limit {
files := OpenParallel(pths)
sort.Sort(ByLengthReverse{files})
for i := 0; i < len(files); i++ {
fmt.Printf("%7d\t%s\n", files[i].LineCount, files[i].FilePath)
}
} else {
fmt.Printf("\nDidn't bother, you tried to meaure %d files, limit set to %d\n\n", len(pths), limit)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment