aboutsummaryrefslogtreecommitdiff
path: root/gui/internal/model/plan.go
diff options
context:
space:
mode:
Diffstat (limited to 'gui/internal/model/plan.go')
-rw-r--r--gui/internal/model/plan.go37
1 files changed, 35 insertions, 2 deletions
diff --git a/gui/internal/model/plan.go b/gui/internal/model/plan.go
index 6d3e857..51a86d8 100644
--- a/gui/internal/model/plan.go
+++ b/gui/internal/model/plan.go
@@ -9,16 +9,20 @@ import (
"context"
"fmt"
"sort"
+ "time"
"krino/internal/engine"
"krino/internal/lock"
"krino/internal/plan"
+ "krino/internal/scan"
)
// Row is one line of the Plan tab: a file krino would act on, or one it
// could not decide about.
type Row struct {
Rel string // the file, relative to the directory's root
+ Size int64
+ ModTime time.Time
Steps []plan.Step
Rule string // the rule that matched first, for the Rule column
Warnings []string
@@ -104,8 +108,10 @@ func (t *PlanTab) fill() {
r := t.dp.Result
t.Warnings = append([]string(nil), r.Warnings...)
warnings := map[string][]string{}
+ files := map[string]scan.File{}
for _, fms := range [][]engine.FileMatch{r.Matched, r.Unmatched} {
for _, fm := range fms {
+ files[fm.File.Rel] = fm.File
if len(fm.Warnings) > 0 {
warnings[fm.File.Rel] = fm.Warnings
}
@@ -119,7 +125,8 @@ func (t *PlanTab) fill() {
}
t.Rows = nil
for _, c := range t.dp.Chains {
- row := Row{Rel: c.File.Rel, Steps: c.Steps, Warnings: warnings[c.File.Rel]}
+ row := Row{Rel: c.File.Rel, Size: c.File.Size, ModTime: c.File.ModTime,
+ Steps: c.Steps, Warnings: warnings[c.File.Rel]}
for _, s := range c.Steps {
if s.Skip == "" {
row.Actable = true
@@ -142,7 +149,9 @@ func (t *PlanTab) fill() {
}
sort.Strings(rest)
for _, rel := range rest {
- t.Rows = append(t.Rows, Row{Rel: rel, Warnings: warnings[rel]})
+ f := files[rel]
+ t.Rows = append(t.Rows, Row{Rel: rel, Size: f.Size, ModTime: f.ModTime,
+ Warnings: warnings[rel]})
}
t.Counts = Counts{
Scanned: len(r.Matched) + len(r.Unmatched) + len(r.Skipped),
@@ -280,3 +289,27 @@ func (t *PlanTab) record(res *engine.ApplyResult) {
}
}
}
+
+// AgeText is how long ago a file was last written, in the units krino's own
+// (age ...) test uses: minutes, hours, days and weeks, and years past that,
+// so a plan can be read at a glance (his request, 2026-09-17).
+func AgeText(mod time.Time, now time.Time) string {
+ if mod.IsZero() {
+ return ""
+ }
+ d := now.Sub(mod)
+ if d < 0 {
+ return "0m" // a file dated in the future is not aged
+ }
+ switch {
+ case d < time.Hour:
+ return fmt.Sprintf("%dm", int(d.Minutes()))
+ case d < 24*time.Hour:
+ return fmt.Sprintf("%dh", int(d.Hours()))
+ case d < 7*24*time.Hour:
+ return fmt.Sprintf("%dd", int(d.Hours()/24))
+ case d < 52*7*24*time.Hour:
+ return fmt.Sprintf("%dw", int(d.Hours()/(24*7)))
+ }
+ return fmt.Sprintf("%dy", int(d.Hours()/(24*365)))
+}