-
Notifications
You must be signed in to change notification settings - Fork 1
/
code_statistic.go
152 lines (134 loc) · 2.95 KB
/
code_statistic.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// a simple go program for computing total line of souce files stored in one dir
package main
import (
"bufio"
"fmt"
"os"
"strings"
"sync"
)
var (
linesum int
mutex *sync.Mutex = new(sync.Mutex)
)
var (
// the dir where souce file stored
rootPath string = "./"
// exclude these sub dirs
nodirs [3]string = [...]string{"/vendor", "/sqlparser", "/mysql"}
// the suffix name you care
suffixname string = "_test.go"
)
func main() {
argsLen := len(os.Args)
fmt.Println("argsLen:", argsLen)
if argsLen == 2 {
rootPath = os.Args[1]
} else if argsLen == 3 {
rootPath = os.Args[1]
suffixname = os.Args[2]
}
// sync chan using for waiting
done := make(chan bool)
go codeLineSum(rootPath, done)
<-done
fmt.Println("total line:", linesum)
}
// compute souce file line number
func codeLineSum(root string, done chan bool) {
var goes int // children goroutines number
godone := make(chan bool) // sync chan using for waiting all his children goroutines finished
isDstDir := checkDir(root)
defer func() {
if pan := recover(); pan != nil {
fmt.Printf("root: %s, panic:%#v\n", root, pan)
}
// waiting for his children done
for i := 0; i < goes; i++ {
<-godone
}
// this goroutine done, notify his parent
done <- true
}()
if !isDstDir {
return
}
rootfi, err := os.Lstat(root)
checkerr(err)
rootdir, err := os.Open(root)
checkerr(err)
defer rootdir.Close()
if rootfi.IsDir() {
fis, err := rootdir.Readdir(0)
checkerr(err)
for _, fi := range fis {
if strings.HasPrefix(fi.Name(), ".") {
continue
}
goes++
if fi.IsDir() {
go codeLineSum(root+"/"+fi.Name(), godone)
} else {
go readfile(root+"/"+fi.Name(), godone)
}
}
} else {
goes = 1 // if rootfi is a file, current goroutine has only one child
go readfile(root, godone)
}
}
func readfile(filename string, done chan bool) {
var line int
isDstFile := strings.HasSuffix(filename, suffixname)
// isTestFile := strings.HasSuffix(filename, "_test"+suffixname)
// if isTestFile {
// isDstFile = false
// }
defer func() {
if pan := recover(); pan != nil {
fmt.Printf("filename: %s, panic:%#v\n", filename, pan)
}
if isDstFile {
addLineNum(line)
fmt.Printf("file %s complete, line = %d\n", filename, line)
}
// this goroutine done, notify his parent
done <- true
}()
if !isDstFile {
return
}
file, err := os.Open(filename)
checkerr(err)
defer file.Close()
reader := bufio.NewReader(file)
for {
_, isPrefix, err := reader.ReadLine()
if err != nil {
break
}
if !isPrefix {
line++
}
}
}
// check whether this dir is the dest dir
func checkDir(dirpath string) bool {
for _, dir := range nodirs {
if rootPath+dir == dirpath {
return false
}
}
return true
}
func addLineNum(num int) {
mutex.Lock()
defer mutex.Unlock()
linesum += num
}
// if error happened, throw a panic, and the panic will be recover in defer function
func checkerr(err error) {
if err != nil {
panic(err.Error())
}
}