summaryrefslogtreecommitdiff
path: root/gui/internal/model/testrule.go
blob: 3cf0437ffea402ca421cf9af6c69ed402becd8fe (plain) (blame)
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"

	"krino/internal/engine"
	"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
}