Route direct-stdout command output through internal/ui (closes #149)
check / check (pull_request) Successful in 1m27s
check / check (push) Successful in 3m18s

version, info, remote info, config, and database delete wrote plain text straight to stdout, so they were unstyled and ignored --quiet. Output is now governed by internal/ui in two buckets. Status lines and confirmations (config init, config set, the database delete prompt) go through the ui message methods and are silenced by --quiet. The data a command exists to produce is written plain -- the version/info/remote-info reports, the snapshot list table, config get values, and the --json documents -- and is never suppressed, since a script depends on it and a marker would corrupt a table or document. The database delete confirmation prompt is always shown. Pure-cli commands reach ui through a small commandUI helper.

Model: opus-4-8
This commit was merged in pull request #201.
This commit is contained in:
2026-09-22 20:28:50 +02:00
parent dd7a610c23
commit eed117fe25
14 changed files with 427 additions and 66 deletions
+24 -7
View File
@@ -13,6 +13,14 @@ import (
// ShowInfo displays system and configuration information
func (v *Vaultik) ShowInfo() error {
// The info report is the output this command exists to produce, so it
// is written plain (markers would corrupt the aligned report) through
// the UI writer's stdout; --quiet silences it like any other
// non-error output.
if v.UI.Quiet() {
return nil
}
// System Information
v.stdoutf("=== System Information ===\n")
v.stdoutf("OS/Architecture: %s/%s\n", runtime.GOOS, runtime.GOARCH)
@@ -213,7 +221,12 @@ func (v *Vaultik) RemoteInfo(jsonOutput bool) error {
result.StorageType = storageInfo.Type
result.StorageLocation = storageInfo.Location
if !jsonOutput {
// The human report is written only when it is neither the --json
// document (which needs stdout to itself) nor silenced by --quiet. The
// scan still runs in both cases so --json still gets a full result.
showText := !jsonOutput && !v.UI.Quiet()
if showText {
v.stdoutf("=== Remote Storage ===\n")
v.stdoutf("Type: %s\n", storageInfo.Type)
v.stdoutf("Location: %s\n", storageInfo.Location)
@@ -226,7 +239,7 @@ func (v *Vaultik) RemoteInfo(jsonOutput bool) error {
return err
}
if !jsonOutput {
if showText {
v.stdoutf("Downloading %d manifest(s)...\n", len(snapshotIDs))
}
@@ -234,7 +247,7 @@ func (v *Vaultik) RemoteInfo(jsonOutput bool) error {
v.populateRemoteInfoResult(result, snapshotMetadata, snapshotIDs, referencedBlobs)
err = v.scanRemoteBlobStorage(result, referencedBlobs, jsonOutput)
err = v.scanRemoteBlobStorage(result, referencedBlobs, showText)
if err != nil {
return err
}
@@ -252,7 +265,9 @@ func (v *Vaultik) RemoteInfo(jsonOutput bool) error {
return enc.Encode(result)
}
v.printRemoteInfoTable(result)
if showText {
v.printRemoteInfoTable(result)
}
return nil
}
@@ -362,11 +377,13 @@ func (v *Vaultik) populateRemoteInfoResult(
}
}
// scanRemoteBlobStorage lists all blobs on remote and computes orphan stats
// scanRemoteBlobStorage lists all blobs on remote and computes orphan
// stats. showText is true only when the human report is being printed
// (not --json, not --quiet), gating the progress line.
func (v *Vaultik) scanRemoteBlobStorage(
result *RemoteInfoResult, referencedBlobs map[string]int64, jsonOutput bool,
result *RemoteInfoResult, referencedBlobs map[string]int64, showText bool,
) error {
if !jsonOutput {
if showText {
v.stdoutf("Scanning blobs...\n")
}