summaryrefslogtreecommitdiff
path: root/internal/engine/engine.go
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-09-14 14:08:36 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-09-14 14:08:36 +0200
commit1d3f2d1e4c59867024470d3444e12698b7ebb22e (patch)
tree4fa14f455c72f9b206a680dcc1b0f4c1f3708158 /internal/engine/engine.go
parent07c24054cab965800983ef40f53a05c2db131ede (diff)
downloadkrino-1d3f2d1e4c59867024470d3444e12698b7ebb22e.tar.gz
krino-1d3f2d1e4c59867024470d3444e12698b7ebb22e.zip
0.0.4: max-size, exclude forms, --min-agev0.0.4
Diffstat (limited to 'internal/engine/engine.go')
-rw-r--r--internal/engine/engine.go47
1 files changed, 43 insertions, 4 deletions
diff --git a/internal/engine/engine.go b/internal/engine/engine.go
index b5f2106..8cffbd1 100644
--- a/internal/engine/engine.go
+++ b/internal/engine/engine.go
@@ -46,6 +46,11 @@ type Dir struct {
// stay memoised, as before.
ContentVariants []cond.Options
+ // Excludes are the (exclude ...) forms that apply here, compiled with the
+ // directory's settings: krino.conf's first, then the directory's own. A
+ // file any of them matches is set aside before any rule runs.
+ Excludes []*Exclude
+
// DupScopes is every distinct directory list the duplicate tests of
// Rules use, in first-seen order, the plain (duplicate) as an empty
// list. Spec §5.5 rule 2 looks a file up under each of them before any
@@ -53,6 +58,12 @@ type Dir struct {
DupScopes [][]string
}
+// Exclude is one compiled (exclude ...) form.
+type Exclude struct {
+ Text string // the form as written, for check, explain and the plan
+ Cond *cond.Cond
+}
+
// Rule is one directory's rule, with its condition compiled.
type Rule struct {
Name string
@@ -71,6 +82,9 @@ func Load(mainFile string, names ...string) (*Engine, []*config.Diag) {
}
var dirs []*Dir
+ // A mistake inside a krino.conf exclude is compiled once per directory,
+ // but reported once.
+ reported := map[string]bool{}
for _, d := range cfg.Dirs {
dir := &Dir{
Name: d.Name,
@@ -103,7 +117,25 @@ func Load(mainFile string, names ...string) (*Engine, []*config.Diag) {
}
dir.Rules = append(dir.Rules, &Rule{Name: r.Name, Conf: r, Settings: rs, Cond: c})
}
- dir.ContentVariants = contentVariants(dir.Rules)
+ dirOpt := cond.Options{IgnoreCase: dir.Settings.Case == config.CaseIgnore, Fold: dir.Settings.Fold}
+ for _, src := range []struct {
+ file string
+ excludes []*config.Exclude
+ }{{cfg.Main.File, cfg.Main.Excludes}, {d.File, d.Excludes}} {
+ for _, x := range src.excludes {
+ c, cerrs := cond.Compile(src.file, x.When, dirOpt)
+ for _, ce := range cerrs {
+ if key := ce.Error(); !reported[key] {
+ reported[key] = true
+ errs = append(errs, ce)
+ }
+ }
+ if len(cerrs) == 0 {
+ dir.Excludes = append(dir.Excludes, &Exclude{Text: x.Text, Cond: c})
+ }
+ }
+ }
+ dir.ContentVariants = contentVariants(dir.Rules, dir.Excludes, dirOpt)
dir.DupScopes = dupScopes(dir.Rules)
dirs = append(dirs, dir)
}
@@ -184,14 +216,21 @@ func dedupeNames(names []string) []string {
return out
}
-// contentVariants returns the distinct (IgnoreCase, Fold) pairs any of
-// rules' content tests evaluate under, in first-seen order — B2's per-Dir
+// contentVariants returns the distinct (IgnoreCase, Fold) pairs any content
+// test evaluates under - each exclude's (under the directory's settings,
+// dirOpt) and each rule's - in first-seen order — B2's per-Dir
// ContentVariants. A rule whose condition has no content test at all
// (Cond.UsesContent false) never calls facts.Content, so its resolved
// case/fold settings contribute no variant here.
-func contentVariants(rules []*Rule) []cond.Options {
+func contentVariants(rules []*Rule, excludes []*Exclude, dirOpt cond.Options) []cond.Options {
var out []cond.Options
seen := map[cond.Options]bool{}
+ for _, x := range excludes {
+ if x.Cond.UsesContent && !seen[dirOpt] {
+ seen[dirOpt] = true
+ out = append(out, dirOpt)
+ }
+ }
for _, r := range rules {
if !r.Cond.UsesContent {
continue