aboutsummaryrefslogtreecommitdiff
path: root/cmd/krino/explain.go
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-09-12 01:22:12 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-09-12 01:22:12 +0200
commit3b36a48b7ce5a53a9366f3b31f94311f178e2553 (patch)
treeecbb277ff916b719f2ee45fba017792b85d5faf9 /cmd/krino/explain.go
parent42b02c47be9b285099203e44a2570636d4ca6f03 (diff)
downloadkrino-3b36a48b7ce5a53a9366f3b31f94311f178e2553.tar.gz
krino-3b36a48b7ce5a53a9366f3b31f94311f178e2553.zip
krino: matching — scan, ignore, conditions, extraction, duplicates, explain, dry run
Diffstat (limited to 'cmd/krino/explain.go')
-rw-r--r--cmd/krino/explain.go70
1 files changed, 70 insertions, 0 deletions
diff --git a/cmd/krino/explain.go b/cmd/krino/explain.go
new file mode 100644
index 0000000..a4d0253
--- /dev/null
+++ b/cmd/krino/explain.go
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package main
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "io"
+ "strings"
+
+ "krino/internal/cond"
+ "krino/internal/engine"
+ "krino/internal/xdg"
+)
+
+func init() { commands["explain"] = cmdExplain }
+
+// cmdExplain evaluates every rule of FILE's directory against it and shows
+// each test's result.
+func cmdExplain(g *globals, args []string, stdout, stderr io.Writer) int {
+ fs := flagSet("explain", g)
+ if code, ok := parse(fs, args, stdout, stderr); !ok {
+ return code
+ }
+ if fs.NArg() != 1 {
+ return usageError(stderr, "usage: krino explain FILE")
+ }
+
+ e, errs := engine.Load(mainFile(g))
+ if len(errs) > 0 {
+ printDiags(stderr, errs)
+ return 2
+ }
+
+ x, err := e.Explain(context.Background(), xdg.Expand(fs.Arg(0)))
+ if err != nil {
+ fmt.Fprintf(stderr, "krino: %v\n", err)
+ return 2
+ }
+
+ fmt.Fprintf(stdout, "%s (directory %s)\n", xdg.Abbrev(x.File.Path), x.Dir.Name)
+ if x.Skip != "" {
+ fmt.Fprintf(stdout, "krino would not look at this file: %s\n", x.Skip)
+ }
+ fmt.Fprintln(stdout)
+ for _, rt := range x.Rules {
+ if rt.Stopped != "" {
+ fmt.Fprintf(stdout, "rule %s: not evaluated, %s\n", rt.Rule.Name, rt.Stopped)
+ continue
+ }
+ status := "no"
+ if rt.Match {
+ status = "MATCH"
+ }
+ fmt.Fprintf(stdout, "rule %s: %s\n", rt.Rule.Name, status)
+ printTrace(stdout, rt.Trace)
+ }
+ return 0
+}
+
+// printTrace writes t's Format output with every line prefixed by two
+// spaces.
+func printTrace(w io.Writer, t *cond.Trace) {
+ var buf bytes.Buffer
+ t.Format(&buf)
+ for _, line := range strings.Split(strings.TrimRight(buf.String(), "\n"), "\n") {
+ fmt.Fprintf(w, " %s\n", line)
+ }
+}