-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
142 lines (130 loc) · 4.24 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
package main
import (
"os"
"flag"
"log"
"fmt"
"time"
"sync"
"strings"
"path/filepath"
"errors"
)
func retrieveLastScanTime(last_scan_path string) time.Time {
last_scan_raw, err := os.ReadFile(last_scan_path)
if err == nil {
candidate, err := time.Parse(time.RFC3339, string(last_scan_raw))
if err == nil {
return candidate
} else {
log.Printf("failed to parse the last scan time; %v", err)
}
} else if !errors.Is(err, os.ErrNotExist) {
log.Printf("failed to read the last scan time; %v", err)
}
return time.Now()
}
func depositLastScanTime(last_scan time.Time, last_scan_path string) {
err := os.WriteFile(last_scan_path, []byte(last_scan.Format(time.RFC3339)), 0644)
if err != nil {
log.Printf("failed to write the last scan time; %v", err)
}
}
func unpackKey(key string) (string, string) {
pos := strings.IndexByte(key, '/')
return key[:pos], key[(pos + 1):]
}
func main() {
gpath := flag.String("registry", "", "Path to the gobbler registry")
surl := flag.String("url", "", "URL of the SewerRat instance")
log_time := flag.Int("log", 10, "Interval in which to check for new logs, in minutes")
full_time := flag.Int("full", 24, "Interval in which to do a full check, in hours")
tpath := flag.String("timestamp", ".sayoko_last_scan", "Path to the last scan timestamp")
flag.Parse()
registry := *gpath
rest_url := *surl
if registry == "" || rest_url == "" {
flag.Usage()
os.Exit(1)
}
if !filepath.IsAbs(registry) {
fmt.Println("expected an absolute file path for the registry")
os.Exit(1)
}
to_reignore := map[string]bool{}
to_reregister := map[string]bool{}
var lock sync.Mutex
ch_reignore := make(chan bool)
ch_reregister := make(chan bool)
// Timer to inspect logs.
go func() {
last_scan_path := *tpath
last_scan := retrieveLastScanTime(last_scan_path)
timer := time.NewTicker(time.Minute * time.Duration(*log_time))
for {
lock.Lock()
new_last_scan, err := checkLogs(registry, rest_url, to_reignore, to_reregister, last_scan)
lock.Unlock()
if err != nil {
log.Printf("detected failures for log check; %v", err)
}
if last_scan != new_last_scan { // new_last_scan can be used regardless of 'err'.
last_scan = new_last_scan
depositLastScanTime(last_scan, last_scan_path)
}
ch_reignore <- true
<-timer.C
}
}()
// Timer to scan the entire registry.
go func() {
timer := time.NewTicker(time.Hour * time.Duration(*full_time))
for {
lock.Lock()
err := fullScan(registry, rest_url, to_reignore)
lock.Unlock()
if err != nil {
log.Printf("detected failures for log check; %v", err)
}
ch_reignore <- true
<-timer.C
}
}()
// Listener to update the ignore files.
go func() {
for {
<- ch_reignore
any_changed := false
lock.Lock()
for k, _ := range to_reignore {
project, asset := unpackKey(k)
changed, err := ignoreNonLatest(registry, project, asset)
if changed { // this can be used regardless of 'err'.
any_changed = true
to_reregister[project] = true
}
if err != nil {
log.Printf("failed to ignore latest for %q; %v", k, err)
}
delete(to_reignore, k)
}
lock.Unlock()
if any_changed {
ch_reregister <- true
}
}
}()
// Listener to re-register projects.
for {
<- ch_reregister
lock.Lock()
for project, _ := range to_reregister {
err := reregisterProject(rest_url, filepath.Join(registry, project))
if err != nil {
log.Printf("failed to reregister %q; %v", project, err)
}
delete(to_reregister, project)
}
lock.Unlock()
}
}