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
|
// SPDX-License-Identifier: GPL-3.0-or-later
package model
import (
"context"
"fmt"
"git.labunix.xyz/krino/internal/engine"
"git.labunix.xyz/krino/internal/plan"
)
// RuleHit is one file a rule would act on, and what it would do to it.
type RuleHit struct {
Rel string
Steps []plan.Step
}
// RuleHits is the answer to "which files would this rule take?".
type RuleHits struct {
Rule string
Files []RuleHit
Scanned int
}
// TestRule plans the directory with the unsaved text and reports the files
// the named rule would act on. It reads only: no lock is taken - the file
// the Plan tab is looking at is none of its business - and nothing is
// written or moved. Content extraction makes it as slow as a scan, so
// callers run it off the main loop.
func (r *Rules) TestRule(ctx context.Context, name string) (*RuleHits, error) {
e, diags := r.load()
if len(diags) > 0 {
return nil, fmt.Errorf("%s", diags[0])
}
var dir *engine.Dir
for _, d := range e.Dirs {
if d.Name == r.Name {
dir = d
break
}
}
if dir == nil {
return nil, fmt.Errorf("model: %s is not in the configuration", r.Name)
}
found := false
for _, rule := range dir.Rules {
if rule.Conf.Name == name {
found = true
break
}
}
if !found {
return nil, fmt.Errorf("model: no rule called %q in %s", name, r.Name)
}
dp, err := e.Plan(ctx, dir, plan.NewClaims())
if err != nil {
return nil, err
}
hits := &RuleHits{Rule: name}
res := dp.Result
hits.Scanned = len(res.Matched) + len(res.Unmatched) + len(res.Skipped)
for _, c := range dp.Chains {
var steps []plan.Step
for _, s := range c.Steps {
if s.Rule == name {
steps = append(steps, s)
}
}
if len(steps) > 0 {
hits.Files = append(hits.Files, RuleHit{Rel: c.File.Rel, Steps: steps})
}
}
return hits, nil
}
|