Skip to content

Commit

Permalink
add wc.go
Browse files Browse the repository at this point in the history
  • Loading branch information
kjk committed Oct 12, 2021
1 parent b11d274 commit 071ab9d
Showing 1 changed file with 187 additions and 0 deletions.
187 changes: 187 additions & 0 deletions u/wc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
package u

import (
"fmt"
"io/ioutil"
"path/filepath"
"sort"
"strings"
)

// LineCount describes line count for a file
type LineCount struct {
Name string
Ext string
LineCount int
}

// LineStats gathers line count info for files
type LineStats struct {
FileToCount map[string]*LineCount
}

// NewLineStats returns new LineStats
func NewLineStats() *LineStats {
return &LineStats{
FileToCount: map[string]*LineCount{},
}
}

func statsPerExt(fileToCount map[string]*LineCount) []*LineCount {
extToCount := map[string]*LineCount{}
for _, wc := range fileToCount {
ext := wc.Ext
extWc := extToCount[ext]
if extWc == nil {
extWc = &LineCount{
Ext: ext,
}
extToCount[ext] = extWc
}
extWc.LineCount += wc.LineCount
}
var res []*LineCount
for _, wc := range extToCount {
res = append(res, wc)
}
sort.Slice(res, func(i, j int) bool {
wc1 := res[i]
wc2 := res[j]
return wc1.LineCount < wc2.LineCount
})
return res
}

type FilterFunc func(string) bool

func MakeAllowedFileFilterForExts(exts ...string) FilterFunc {
for i, ext := range exts {
exts[i] = strings.ToLower(ext)
}

return func(path string) bool {
fext := strings.ToLower(filepath.Ext(path))
for _, ext := range exts {
if ext == fext {
return true
}
}
return false
}
}

func MakeExcludeDirsFilter(dirs ...string) FilterFunc {
return func(path string) bool {
// path starts as a file path
// we only compare directory names
path = filepath.Dir(path)
for len(path) > 0 {
if path == "." {
return true
}
name := filepath.Base(path)
for _, dir := range dirs {
if name == dir {
return false
}
}
path = filepath.Dir(path)
}
return true
}
}

func MakeFilterOr(filters ...FilterFunc) FilterFunc {
return func(name string) bool {
for _, f := range filters {
if f(name) {
return true
}
}
return false
}
}

func MakeFilterAnd(filters ...FilterFunc) FilterFunc {
return func(name string) bool {
for _, f := range filters {
if !f(name) {
return false
}
}
return true
}
}

// FileLineCount returns number of lines in a file
func FileLineCount(path string) (int, error) {
d, err := ioutil.ReadFile(path)
if err != nil {
return 0, err
}
if len(d) == 0 {
return 0, nil
}
d = NormalizeNewlines(d)
nLines := 1
n := len(d)
for i := 0; i < n; i++ {
if d[i] == 10 {
nLines++
}
}
return nLines, nil
}

func (s *LineStats) CalcInDir(dir string, allowedFileFilter func(name string) bool, recur bool) error {
files, err := ioutil.ReadDir(dir)
if err != nil {
return err
}
for _, fi := range files {
name := fi.Name()
path := filepath.Join(dir, name)
if fi.IsDir() {
if recur {
s.CalcInDir(path, allowedFileFilter, recur)
}
continue
}
if !fi.Mode().IsRegular() {
continue
}
if !allowedFileFilter(path) {
continue
}
lineCount, err := FileLineCount(path)
if err != nil {
return err
}
s.FileToCount[path] = &LineCount{
Name: fi.Name(),
Ext: strings.ToLower(filepath.Ext(name)),
LineCount: lineCount,
}
}
return nil
}

func PrintLineStats(stats *LineStats) {
var files []string
for k := range stats.FileToCount {
files = append(files, k)
}
sort.Strings(files)
total := 0
for _, f := range files {
wc := stats.FileToCount[f]
fmt.Printf("% 6d %s\n", wc.LineCount, f)
total += wc.LineCount
}
fmt.Printf("\nPer extension:\n")
wcPerExt := statsPerExt(stats.FileToCount)
for _, wc := range wcPerExt {
fmt.Printf("%d %s\n", wc.LineCount, wc.Ext)
}
fmt.Printf("\ntotal: %d\n", total)
}

0 comments on commit 071ab9d

Please sign in to comment.