// 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 }