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
|
// SPDX-License-Identifier: GPL-3.0-or-later
// Package cond compiles the s-expression conditions of a rule's (when ...)
// into a tree that Task 8's evaluator walks against one file's facts.
package cond
import (
"regexp"
"time"
"krino/internal/sexp"
)
// Options carries a rule's resolved case and fold settings into compilation.
type Options struct {
IgnoreCase bool // the rule's resolved case setting is "ignore"
Fold bool // the rule's resolved fold setting
}
// Cond is a compiled condition. A Cond compiled from no conditions (a rule
// without when) is always true.
type Cond struct {
root *node // nil: always true
opt Options // the case/fold settings conditions were compiled with; Task 8 needs them again at eval time
UsesContent bool // some content test exists
DupDirs [][]string // the raw directory arguments of each duplicate test, in order
}
// kind is what a compiled node tests, or how it combines its children.
type kind int
const (
kAnd kind = iota
kOr
kNot
kType
kName
kPath
kContent
kSize
kAge
kDuplicate
kMatched
)
// Costs, per the brief's cost order: cheapest first when sorting and/or
// children. not takes its child's cost; and/or take the sum of theirs.
const (
costCheap = 1 // type, size, age, matched
costRegex = 2 // name, path
costDuplicate = 5
costContent = 10
)
// pattern is one name/path regex, compiled and paired with the text it was
// written as (undecorated by (?i) or folding), for labels and reasons.
type pattern struct {
re *regexp.Regexp
src string
}
// keyword is one content keyword, normalised for matching and paired with
// the text it was written as, for labels and reasons.
type keyword struct {
norm string
src string
}
// node is one compiled condition: a leaf test, or an and/or/not combinator
// over other nodes. Task 8 evaluates this tree.
type node struct {
kind kind
pos sexp.Pos // the position of the node as written, for diagnostics
label string // the test as written, e.g. `content "acme ltd" "0000000000"`
cost int // this node's evaluation cost; and/or sort children by it
children []*node // and, or, not
// type
suffixes []string // leading-dot, lower-case, e.g. ".pdf"
// name, path
patterns []pattern
// content
keywords []keyword
// size, age (kind tells which is populated)
op string
sizeVal int64
ageVal time.Duration
// duplicate
dirs []string
}
// groups maps a (type ...) group name to the extensions it expands to,
// spec Appendix A.
var groups = map[string][]string{
"image": {"jpg", "jpeg", "png", "gif", "webp", "bmp", "tif", "tiff", "heic", "heif", "avif", "svg", "ico", "raw", "cr2", "nef", "arw", "dng"},
"video": {"mp4", "mkv", "webm", "mov", "avi", "m4v", "mpg", "mpeg", "wmv", "flv", "3gp"},
"audio": {"mp3", "flac", "ogg", "opus", "m4a", "aac", "wav", "wma", "aiff"},
"archive": {"zip", "tar", "gz", "tgz", "bz2", "tbz2", "xz", "txz", "zst", "7z", "rar", "lz", "lzma", "cpio"},
"document": {"pdf", "doc", "docx", "odt", "rtf", "txt", "md", "tex"},
"spreadsheet": {"xls", "xlsx", "ods", "csv", "tsv"},
"presentation": {"ppt", "pptx", "odp"},
"ebook": {"epub", "mobi", "azw", "azw3", "fb2", "djvu"},
"code": {"go", "c", "h", "cpp", "hpp", "py", "sh", "js", "ts", "rs", "java", "rb", "pl", "lua", "html", "css", "json", "yaml", "yml", "toml", "xml", "sql"},
"text": {"txt", "md", "log", "csv", "tsv", "json", "yaml", "yml", "toml", "xml", "ini", "conf"},
"package": {"deb", "rpm", "apk", "appimage", "exe", "msi", "flatpak", "snap"},
"font": {"ttf", "otf", "woff", "woff2"},
}
|