// SPDX-License-Identifier: GPL-3.0-or-later package main import ( "fmt" "io" "path/filepath" "strings" "time" "krino/internal/config" "krino/internal/engine" "krino/internal/xdg" ) // minAgeOverride parses --min-age: a duration in krino's own units (30s, // 2m, 1h, 1d, 1w), or a bare 0. set is false when the flag was not given. // Checked before any config is read, as every flag is. func minAgeOverride(g *globals) (d time.Duration, set bool, err error) { switch { case !g.minAgeSet: return 0, false, nil case g.minAge == "": return 0, false, fmt.Errorf("--min-age: needs a duration, like 0, 30m or 1d") case g.minAge == "0": return 0, true, nil } d, err = config.ParseDuration(g.minAge) if err != nil { return 0, false, fmt.Errorf("--min-age: %v", err) } return d, true, nil } // refuseUnusedFlags refuses the global flags a command does not use - // -y and -n unless usesYesDry, and --json and -v - instead of silently // ignoring them, so "krino -n new ...", meant as a preview, cannot write // config (re-review cli F4). It reports whether it refused. func refuseUnusedFlags(g *globals, stderr io.Writer, cmd string, usesYesDry bool) (int, bool) { var given []string if !usesYesDry && g.yes { given = append(given, "-y") } if !usesYesDry && g.dry { given = append(given, "-n") } if g.json { given = append(given, "--json") } if g.verbose { given = append(given, "-v") } if len(given) == 0 { return 0, false } return usageError(stderr, fmt.Sprintf("%s does not take %s", cmd, strings.Join(given, ", "))), true } // cacheDir is where every directory's keyword cache lives (spec ยง6.1). func cacheDir() string { return filepath.Join(xdg.CacheHome(), "krino") } // applyMinAge sets every loaded directory's min-age to d, for this run only. func applyMinAge(e *engine.Engine, d time.Duration) { for _, dir := range e.Dirs { dir.Settings.MinAge = d } } // mainFile is -c FILE, or the default krino.conf. func mainFile(g *globals) string { if g.conf != "" { return xdg.Expand(g.conf) } return config.DefaultFile() } // usageError reports a command-line mistake and returns exit status 2. func usageError(stderr io.Writer, msg string) int { fmt.Fprintf(stderr, "krino: %s\n", msg) fmt.Fprintln(stderr, "run 'krino -h' for help") return 2 } // printDiags prints config problems with ~ for the home directory, then a count. func printDiags(stderr io.Writer, errs []*config.Diag) { for _, e := range errs { d := *e d.File = xdg.Abbrev(d.File) fmt.Fprintln(stderr, &d) } if len(errs) == 1 { fmt.Fprintln(stderr, "krino: 1 problem found") } else { fmt.Fprintf(stderr, "krino: %d problems found\n", len(errs)) } } // describeActions renders a rule's actions briefly, as in: move PDF, stop. func describeActions(r *config.Rule) string { var parts []string for _, a := range r.Actions { if a.Arg == "" { parts = append(parts, a.Kind.String()) } else { parts = append(parts, a.Kind.String()+" "+a.Arg) } } if r.Stop { parts = append(parts, "stop") } return strings.Join(parts, ", ") }