-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
159 lines (136 loc) · 3.59 KB
/
main.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
153
154
155
156
157
158
159
// This is an example of how to use the parser. There are many more functions within the package that aren't being used here.
package main
import (
"bufio"
"bytes"
"flag"
"fmt"
"io/ioutil"
"os"
"path"
"sort"
"strings"
"sync"
log "github.com/marcsantiago/logger"
"github.com/marcsantiago/search_keyword/search"
)
const logKey = "Main"
func readFromDirectory(dir string, sc *search.Scanner) (err error) {
var wg sync.WaitGroup
files, err := ioutil.ReadDir(dir)
if err != nil {
return
}
for _, f := range files {
name := f.Name()
p := path.Join(dir, name)
// avoid .DS_Store and like files
if strings.HasPrefix(name, ".") {
continue
}
file, err := os.Open(p)
if err != nil {
log.Fatal(logKey, "couldn't open file", "error", err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
wg.Add(1)
go scan(scanner.Text(), &wg, sc)
}
if err := scanner.Err(); err != nil {
return err
}
}
wg.Wait()
return
}
func readFromFile(path string, sc *search.Scanner) (err error) {
var wg sync.WaitGroup
file, err := os.Open(path)
if err != nil {
return
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
wg.Add(1)
go scan(scanner.Text(), &wg, sc)
}
wg.Wait()
if err = scanner.Err(); err != nil {
return
}
return
}
func scan(line string, wg *sync.WaitGroup, sc *search.Scanner) {
defer wg.Done()
parts := strings.Split(line, ",")
if len(parts) <= 0 {
return
}
URL := strings.Replace(parts[1], "\"", "", -1)
err := sc.Search(URL)
if err != nil {
log.Error(logKey, "search error", "error", err)
}
}
// this particular main function is written in such a way to satisfy
// the questions requirement, however the package search was written to
// be more generic
func main() {
inputFile := flag.String("in", "", "the input file path containing the list of urls or folder path containing files pointing to urls")
outFile := flag.String("out", "", "output file path")
keyword := flag.String("keyword", "", "keyword to search for")
enableLogging := flag.Bool("logging", false, "enables logging")
limit := flag.Int("concurrency", 20, "set the limit of goroutines to spin up")
depth := flag.Int("depth", 0, "set how depth of the search")
flag.Parse()
if *inputFile == "" {
flag.PrintDefaults()
log.Fatal(logKey, "input file path cannot be empty")
}
if *outFile == "" {
flag.PrintDefaults()
log.Fatal(logKey, "out file path cannot be empty")
}
if *keyword == "" {
flag.PrintDefaults()
log.Fatal(logKey, "keyword cannot be empty")
}
fi, err := os.Stat(*inputFile)
if err != nil {
log.Fatal(logKey, "os.Stat", "error", err)
}
sc := search.NewScanner(*limit, *depth, *enableLogging, *keyword)
switch mode := fi.Mode(); {
case mode.IsDir():
err := readFromDirectory(*inputFile, sc)
if err != nil {
log.Fatal(logKey, "could not read from directory", "error", err)
}
case mode.IsRegular():
err := readFromFile(*inputFile, sc)
if err != nil {
log.Fatal(logKey, "could not read from file", "error", err)
}
}
var buf bytes.Buffer
header := fmt.Sprintf("search for keyword %s\nurl,found,context\n", *keyword)
_, err = buf.WriteString(header)
if err != nil {
log.Error(logKey, "buffer could not write initial string")
}
sort.Sort(sc.Results)
for _, r := range sc.Results {
line := fmt.Sprintf("%s, %v, %v\n", r.URL, r.Found, r.Context)
_, err = buf.WriteString(line)
if err != nil {
log.Fatal(logKey, "couldn't write string", "message", line)
}
}
err = ioutil.WriteFile(*outFile, buf.Bytes(), 0644)
if err != nil {
log.Fatal(logKey, "couldn't write file", "error", err)
}
}