Skip to content

Instantly share code, notes, and snippets.

@rudenoise
Created August 24, 2012 13:35
Show Gist options
  • Save rudenoise/3450591 to your computer and use it in GitHub Desktop.
Save rudenoise/3450591 to your computer and use it in GitHub Desktop.
My first go (console) app for analysing file length/size(bytes): sizeFiles
package main
import (
"bufio"
"flag"
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"sort"
)
// cmd flags
var byBytes = flag.Bool("bytes", false, "order by byte length or line length")
var asc = flag.Bool("asc", false, "order ascending/descending")
var colour = flag.Bool("c", false, "colour output")
var lmt = flag.Int("limit", 0, "limit number of results")
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
ByteLen int64
Lines int
}
type Paths []File
func (p Paths) Len() int { return len(p) }
func (p Paths) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
type ByByteLen struct{ Paths }
func (p ByByteLen) Less(i, j int) bool { return p.Paths[i].ByteLen < p.Paths[j].ByteLen }
type ByByteLenReverse struct{ Paths }
func (p ByByteLenReverse) Less(i, j int) bool { return p.Paths[i].ByteLen > p.Paths[j].ByteLen }
type ByLines struct{ Paths }
func (p ByLines) Less(i, j int) bool { return p.Paths[i].Lines < p.Paths[j].Lines }
type ByLinesReverse struct{ Paths }
func (p ByLinesReverse) Less(i, j int) bool { return p.Paths[i].Lines > p.Paths[j].Lines }
// SET UP pths TO HOLD COLLECTED DATA
var pths Paths
// COUNT LINES IN FILE
func countLines(filePath string) int {
count := 0
contents, err := os.Open(filePath)
if err != nil {
panic(err)
}
defer contents.Close()
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 visit(path string, f os.FileInfo, err error) error {
excludeMatch, err := regexp.MatchString(*exclude, path)
if err != nil {
panic(err)
}
includeMatch, err := regexp.MatchString(*include, path)
if err != nil {
panic(err)
}
if f.IsDir() == false && excludeMatch == false && includeMatch {
file := File{path, f.Size(), countLines(path)}
pths = append(pths, file)
}
return err
}
func out(p Paths, limit int) {
// print in colour
fmt.Printf("%7s\t%7s\t%s\n", "Lines", "Bytes", "Path")
for i := 0; i < limit; i++ {
// print out all collected file info
if p[i].FilePath != "." {
fmt.Printf("%7d\t%7d\t%s\n", p[i].Lines, p[i].ByteLen, p[i].FilePath)
}
}
}
func colourOut(p Paths, limit int) {
// print in colour
fmt.Printf("\033[1;32m%7s\t\033[1;33m%7s\t\033[1;37m%s\n\033[m", "Lines", "Bytes", "Path")
for i := 0; i < limit; i++ {
// print out all collected file info
if p[i].FilePath != "." {
fmt.Printf("\033[0;32m%7d\t\033[0;33m%7d\t\033[m%s\n", p[i].Lines, p[i].ByteLen, p[i].FilePath)
}
}
}
func main() {
flag.Parse()
// start at current dir or path from args
root := filepath.Dir(flag.Arg(0))
// recurse each sub dir and run visit at each file location
err := filepath.Walk(root, visit)
// files parsed ok
if err != nil {
panic(err)
}
// order by args
if *byBytes {
if *asc {
sort.Sort(ByByteLen{pths})
} else {
sort.Sort(ByByteLenReverse{pths})
}
} else {
if *asc {
sort.Sort(ByLines{pths})
} else {
sort.Sort(ByLinesReverse{pths})
}
}
// decide length of output
length := len(pths)
if *lmt != 0 && *lmt <= length {
length = *lmt
}
// print output
if *colour {
colourOut(pths, length)
} else {
out(pths, length)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment