-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathpush.go
155 lines (129 loc) · 4.18 KB
/
push.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
package main
import (
"bufio"
"fmt"
"log"
"os"
"strconv"
"strings"
"sync"
"time"
"github.com/go-redis/redis"
"github.com/google/uuid"
)
func pushIt(command string, queue string, parametersString string, test bool, timeout int, verbose bool) {
var split []string
var filenames []string
var placeholders []string
// split the parameters input into a slice of placeholder:filename pairs
parameters := strings.Split(parametersString, ",")
// separate the placeholder from the filename and store them in two slices for processing
for _, p := range parameters {
split = strings.Split(p, ":")
placeholders = append(placeholders, split[0])
filenames = append(filenames, split[1])
}
// get a slice of lines for each filename
var fileSlices [][]string
for _, filename := range filenames {
newFileLines, err := readLines(filename)
if err != nil {
log.Fatal(err)
}
fileSlices = append(fileSlices, newFileLines)
}
// for each file, figure out how many lines there are. Store lengths of each file in a slice called lengths, and do the same for originalLengths
var lengths []int
var originalLengths []int
for i := range fileSlices {
length := len(fileSlices[i])
lengths = append(lengths, length)
originalLengths = append(originalLengths, length)
}
var wg sync.WaitGroup
// create a rendom queue name for sending back data
queueID := uuid.New().String()
// get the results back and print them
go printResults(queueID, &wg, verbose)
// this is the recursive function that generates all of the command combinations
loopThrough(fileSlices, placeholders, command, lengths, originalLengths, test, &wg, queueID, timeout, queue)
// wait for all results to be returned and printed before exiting
wg.Wait()
}
func printResults(queueID string, wg *sync.WaitGroup, verbose bool) {
for {
result, err := redisClient.RPop(queueID).Result()
switch {
case err == redis.Nil: // the queue doesn't exist, there's no output to print yet
if verbose {
log.Println("Awaiting output:", err)
}
time.Sleep(1 * time.Second)
case err != nil: // there was an actual error trying to grab the data
log.Println("Redis error:", err)
case result == "": // the command returned no output, don't bother printing a blank line
wg.Done()
default: // we got output, print it!
fmt.Println(result)
wg.Done()
}
}
}
// checks if all elements of a slice are equal to comparator
func checkIfAll(array []int, comparator int) bool {
for _, i := range array {
if i != comparator {
return false
}
}
return true
}
// Recursive function that takes slices of strings, and prints every combination of lines in each file
func loopThrough(fileSlices [][]string, placeholders []string, command string, lengths []int, originalLengths []int, test bool, wg *sync.WaitGroup, queueID string, timeout int, queue string) {
if checkIfAll(lengths, 0) {
return
}
line := command
for i, fileSlice := range fileSlices {
// if the RHS number is 0, finish
if lengths[len(lengths)-1] == 0 {
return
}
// replace the placeholders in the line
line = strings.ReplaceAll(line, "_"+placeholders[i]+"_", fileSlice[lengths[i]-1])
}
// if -test is specified, just print the commands, otherwise push them to redis
if test {
fmt.Println(line)
} else {
// using :::_::: as a separator between the queueID, timeout and command
redisClient.LPush(queue, queueID+":::_:::"+strconv.Itoa(timeout)+":::_:::"+line)
wg.Add(1)
}
for i := range lengths {
// if our current number is a 0, decrement the number directly to the right, then set this back to the original
if lengths[i] == 1 && len(lengths) != i+1 {
lengths[i+1] = lengths[i+1] - 1
lengths[i] = originalLengths[i]
break
} else {
lengths[i] = lengths[i] - 1
break
}
}
loopThrough(fileSlices, placeholders, command, lengths, originalLengths, test, wg, queueID, timeout, queue)
}
// readLines reads a whole file into memory and returns a slice of its lines.
func readLines(path string) ([]string, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
var lines []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines, scanner.Err()
}