forked from Cloudbox/autoscan
-
Notifications
You must be signed in to change notification settings - Fork 0
/
autoscan.go
145 lines (117 loc) · 3.31 KB
/
autoscan.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
package autoscan
import (
"errors"
"fmt"
"net/http"
"regexp"
"time"
)
// A Scan is at the core of Autoscan.
// It defines which path to scan and with which (trigger-given) priority.
//
// The Scan is used across Triggers, Targets and the Processor.
type Scan struct {
Folder string
RelativePath string
Priority int
Time time.Time
}
type ProcessorFunc func(...Scan) error
type Trigger func(ProcessorFunc)
// A HTTPTrigger is a Trigger which does not run in the background,
// and instead returns a http.Handler.
//
// This http.Handler should be added to the autoscan router in cmd/autoscan.
type HTTPTrigger func(ProcessorFunc) http.Handler
// A Target receives a Scan from the Processor and translates the Scan
// into a format understood by the target.
type Target interface {
Scan(Scan) error
Available() error
}
var (
// ErrTargetUnavailable may occur when a Target goes offline
// or suffers from fatal errors. In this case, the processor
// will halt operations until the target is back online.
ErrTargetUnavailable = errors.New("target unavailable")
// ErrFatal indicates a severe problem related to development.
ErrFatal = errors.New("fatal error")
// ErrNoScans is not an error. It only indicates whether the CLI
// should sleep longer depending on the processor output.
ErrNoScans = errors.New("no scans currently available")
// ErrAnchorUnavailable indicates that an Anchor file is
// not available on the file system. Processing should halt
// until all anchors are available.
ErrAnchorUnavailable = errors.New("anchor file is unavailable")
)
type Rewrite struct {
From string `yaml:"from"`
To string `yaml:"to"`
}
type Rewriter func(string) string
func NewRewriter(rewriteRules []Rewrite) (Rewriter, error) {
var rewrites []regexp.Regexp
for _, rule := range rewriteRules {
re, err := regexp.Compile(rule.From)
if err != nil {
return nil, err
}
rewrites = append(rewrites, *re)
}
rewriter := func(input string) string {
for i, r := range rewrites {
if r.MatchString(input) {
return r.ReplaceAllString(input, rewriteRules[i].To)
}
}
return input
}
return rewriter, nil
}
type Filterer func(string) bool
func NewFilterer(includes []string, excludes []string) (Filterer, error) {
reIncludes := make([]regexp.Regexp, 0)
reExcludes := make([]regexp.Regexp, 0)
// compile patterns
for _, pattern := range includes {
re, err := regexp.Compile(pattern)
if err != nil {
return nil, fmt.Errorf("compiling include: %v: %w", pattern, err)
}
reIncludes = append(reIncludes, *re)
}
for _, pattern := range excludes {
re, err := regexp.Compile(pattern)
if err != nil {
return nil, fmt.Errorf("compiling exclude: %v: %w", pattern, err)
}
reExcludes = append(reExcludes, *re)
}
incSize := len(reIncludes)
excSize := len(reExcludes)
// create filterer
var fn Filterer = func(string) bool { return true }
if incSize > 0 || excSize > 0 {
fn = func(path string) bool {
// check excludes
for _, re := range reExcludes {
if re.MatchString(path) {
return false
}
}
// no includes (but excludes did not match)
if incSize == 0 {
return true
}
// check includes
for _, re := range reIncludes {
if re.MatchString(path) {
return true
}
}
// no includes passed
return false
}
}
return fn, nil
}