11package main
22
33import (
4- "flag"
54 "fmt"
6- "os"
7- "runtime"
8- "strings"
9- "sync"
105)
116
127var IGNORE_PATHS = [7 ]string {
@@ -31,41 +26,24 @@ func printBuildInfo() {
3126}
3227
3328func main () {
34- //The number of workers. If there are more workers the system can read from
35- //the work queue more often and a larger queue is not required.
36- workers := flag .Int ("w" , - 1 , "Number of workers" )
37- //If the queue overflows we'll use a slice to store work which might slow the system
38- queueSize := flag .Int ("q" , 512 , "The max work queue size" )
39- maxResults := flag .Int ("c" , - 1 , "The maximum number of results to find" )
40- dir := flag .String ("d" , "." , "The starting directory to check for files" )
41- pattern := flag .String ("p" , "" , "A pattern to check for within the file names" )
42- v := flag .Bool ("v" , false , "print the version and build information" )
43- flag .Parse ()
44-
45- if * v {
29+ cfg := parseArgs ()
30+ if cfg .Version {
4631 printBuildInfo ()
4732 return
4833 }
4934
50- if * pattern == "" {
51- fmt .Println ("No pattern provided " )
35+ if cfg . Pattern == "" {
36+ fmt .Println ("No pattern found, please provide a search pattern " )
5237 return
5338 }
5439
55- w := * workers
56- if * workers <= 0 {
57- w = runtime .NumCPU () + 2
58- }
59-
60- //Only for OSX/Linux, sorry windows
61- //Remove any trailing slashes in the path
62- if (* dir )[len (* dir )- 1 :] == "/" {
63- * dir = string ((* dir )[0 : len (* dir )- 1 ])
40+ if cfg .Insensative {
41+ fmt .Println ("WARN: case insensative search is not yet supported" )
6442 }
6543
66- printCh := make (chan string , w )
44+ printCh := make (chan string , cfg . Workers )
6745 //The system will reach deadlock if the work queue reaches capacity
68- workQ := make (chan string , * queueSize )
46+ workQ := make (chan string , cfg . QueueSize )
6947 //To avoid deadlock, send tasks here which will have a non-blocky retry
7048 //func to add tasks back to workQ
7149 failover := make (chan string )
@@ -77,110 +55,11 @@ func main() {
7755 //defer close(dirCount)
7856 //defer close(failover)
7957 go handleFailover (workQ , failover )
80- go createWorkerPool (pattern , workQ , failover , printCh , dirCount , w )
58+ go createWorkerPool (cfg . Pattern , workQ , failover , printCh , dirCount , cfg . Workers )
8159
8260 //Send first work request
83- workQ <- * dir
61+ workQ <- cfg . Dir
8462
8563 //Print all results
86- showResults (printCh , maxResults )
87- }
88-
89- func showResults (ch chan string , limit * int ) {
90- if * limit > 0 {
91- n := 0
92- for item := range ch {
93- fmt .Println (item )
94- n ++
95- if n >= * limit {
96- return
97- }
98- }
99- } else {
100- for item := range ch {
101- fmt .Println (item )
102- }
103- }
104- }
105-
106- func dirChecker (in chan int , work chan string ) {
107- n := 1
108- for i := range in {
109- n += i
110- if n <= 0 {
111- close (work )
112- return
113- }
114- }
115- }
116-
117- func createWorkerPool (p * string , in chan string , failover chan string , results chan string , cnt chan int , w int ) {
118- var wg sync.WaitGroup
119- for i := 0 ; i < w ; i ++ {
120- wg .Add (1 )
121- go func () {
122- defer wg .Done ()
123- search (p , in , failover , results , cnt )
124- }()
125- }
126- wg .Wait ()
127- close (results )
128- }
129- func search (pattern * string , in chan string , failover chan string , out chan string , cnt chan int ) {
130- for path := range in {
131- items , err := os .ReadDir (path )
132- if err != nil {
133- fmt .Println ("Error reading the directory" , path )
134- fmt .Println (err )
135- cnt <- - 1
136- }
137- ItemSearch:
138- for _ , item := range items {
139- if item .IsDir () {
140- //Don't dive into directories I don't care about
141- for _ , p := range IGNORE_PATHS {
142- if p == item .Name () {
143- continue ItemSearch
144- }
145- }
146- subPath := fmt .Sprintf ("%s/%s" , path , item .Name ())
147- cnt <- 1
148- select {
149- case in <- subPath :
150- case failover <- subPath :
151- }
152- }
153- //Always check if the name of the thing matches pattern, including directory names
154- if strings .Index (item .Name (), * pattern ) >= 0 {
155- //subPath is repeated but no point in creating an allocation if not required
156- subPath := fmt .Sprintf ("%s/%s" , path , item .Name ())
157- out <- subPath
158- }
159-
160- }
161- //We finished reading everything in the dir, tell the accounted we finished
162- cnt <- - 1
163- }
164- }
165-
166- func handleFailover (work , fail chan string ) {
167- var q []string
168- for {
169- task := <- fail
170- q = append (q , task )
171- //TODO: Add verbose logging here so users can check if the failover was used
172- for {
173- select {
174- case work <- q [0 ]:
175- q = q [1 :]
176- case task := <- fail :
177- q = append (q , task )
178- default :
179- }
180- //I don't know if we'll get an issue with `work <- q[0]` unless we have this
181- if len (q ) == 0 {
182- break
183- }
184- }
185- }
64+ showResults (printCh , & cfg .MaxResults )
18665}
0 commit comments