Introduce internal/ui package and rewrite user-facing output

All user-facing output now goes through a single ui.Writer with a
uniform style:

  》 (white)     for begin / info / notice
  》 (green)     for complete / success
  Warning:      for warnings (orange)
  ERROR:        for errors (red)
    》          (indented) for progress heartbeats

Color is enabled when stdout is a TTY and NO_COLOR is unset.

Standards:
- Complete-sentence messages with fully qualified terms ("backup
  destination store", "local index database", "snapshot source
  files enumeration").
- Every Complete has a matching Begin.
- Natural verb tense conveys state ("Uploading" -> "Uploaded"). The
  words "begin"/"complete" never appear in message bodies; the marker
  color carries that information.
- ETA means clock time, not duration. Progress lines say "estimated
  remaining time (<dur>), finish at <time>" with both labeled.

Adds globals.CommitDate (populated by Makefile/Dockerfile/goreleaser
via ldflags from `git show -s --format=%cI HEAD`) and a startup banner
printed once per invocation.

Strips fx call-chain noise from startup errors so users see the actual
underlying error (e.g. "creating base path: mkdir /Volumes/BACKUPS:
permission denied" instead of three layers of "could not build
arguments for function ...").

README documents the output style and the ui package conventions.
This commit is contained in:
2026-06-17 04:32:05 +02:00
parent 8de8f8e5cc
commit 00d4b36e35
14 changed files with 533 additions and 187 deletions

View File

@@ -13,19 +13,36 @@ var Version string = "dev"
// Commit is the git commit hash, populated from main().
var Commit string = "unknown"
// CommitDate is the ISO-8601 date of the commit, populated from main().
var CommitDate string = "unknown"
// Author identifies the upstream author of vaultik.
const Author = "Jeffrey Paul <sneak@sneak.berlin>"
// Globals contains application-wide configuration and metadata.
type Globals struct {
Appname string
Version string
Commit string
StartTime time.Time
Appname string
Version string
Commit string
CommitDate string
StartTime time.Time
}
// New creates and returns a new Globals instance initialized with the package-level variables.
func New() (*Globals, error) {
return &Globals{
Appname: Appname,
Version: Version,
Commit: Commit,
Appname: Appname,
Version: Version,
Commit: Commit,
CommitDate: CommitDate,
}, nil
}
// ShortCommit returns the first 12 chars of the commit hash, or the
// whole string if it's shorter (e.g. "unknown").
func (g *Globals) ShortCommit() string {
if len(g.Commit) > 12 {
return g.Commit[:12]
}
return g.Commit
}