From 1bb5097986558ee7dd3aeaf8e7defefdf91ae4b6 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Mon, 14 Sep 2026 23:48:23 +0200 Subject: duplicate warnings share one format --- internal/engine/facts.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'internal/engine/facts.go') diff --git a/internal/engine/facts.go b/internal/engine/facts.go index c510b20..f8fde89 100644 --- a/internal/engine/facts.go +++ b/internal/engine/facts.go @@ -5,6 +5,7 @@ package engine import ( "context" "errors" + "io/fs" "path/filepath" "sort" "strings" @@ -73,11 +74,27 @@ func (run *matchRun) drainDupErrors() { defer run.mu.Unlock() for _, idx := range run.dupIdx { for _, ce := range idx.Errors() { - run.warn = append(run.warn, "duplicate: "+xdg.Abbrev(ce.Path)+": "+ce.Err.Error()) + run.warn = append(run.warn, dupWarning(ce)) } } } +// dupWarning is the one form of a duplicate warning (triage 6): "duplicate: +// PATH: cause", the path abbreviated like every other one shown, and an OS +// error's cause without the raw path it would repeat. +func dupWarning(err error) string { + var ce dup.CandidateError + if !errors.As(err, &ce) { + return "duplicate: " + err.Error() + } + cause := ce.Err.Error() + var pe *fs.PathError + if errors.As(ce.Err, &pe) { + cause = pe.Op + ": " + pe.Err.Error() + } + return "duplicate: " + xdg.Abbrev(ce.Path) + ": " + cause +} + // dupIndex returns the shared *dup.Index for the resolved, sorted extra // directories named by key, building it exactly once across every // concurrent caller that asks for the same key. @@ -95,7 +112,7 @@ func (run *matchRun) dupIndex(key string, dirs []string) *dup.Index { run.mu.Lock() run.dupIdx[key] = idx for _, err := range errs { - run.warn = append(run.warn, "duplicate: "+err.Error()) + run.warn = append(run.warn, dupWarning(err)) } run.mu.Unlock() }) -- cgit v1.3