Merge fix/cron-quietness-and-upload-destination
All checks were successful
check / check (push) Successful in 1m58s

This commit is contained in:
2026-06-24 08:58:31 +02:00
3 changed files with 17 additions and 7 deletions

View File

@@ -46,8 +46,12 @@ func Initialize(cfg Config) {
var level slog.Level
if cfg.Cron || cfg.Quiet {
// In quiet/cron mode, only show errors
level = slog.LevelError
// In cron/quiet mode keep warnings and errors visible — the
// whole point of --cron is to stay silent only on total
// success, so that anything cron emails to root is genuinely
// "something went wrong, look at it." A backup with stuck
// permission errors or skipped files should NOT be silent.
level = slog.LevelWarn
} else if cfg.Debug || strings.Contains(os.Getenv("GODEBUG"), "vaultik") {
level = slog.LevelDebug
} else if cfg.Verbose {

View File

@@ -1177,16 +1177,17 @@ func (s *Scanner) uploadBlobIfNeeded(ctx context.Context, blobPath string, blobW
finishedBlob := blobWithReader.FinishedBlob
// Check if blob already exists (deduplication after restart)
destination := s.storage.Info().Location
if _, err := s.storage.Stat(ctx, blobPath); err == nil {
log.Info("Blob already exists in storage, skipping upload",
"hash", finishedBlob.Hash, "size", humanize.Bytes(uint64(finishedBlob.Compressed)))
s.ui.Info("Blob %s (%s) already exists in backup destination store. Skipping upload.",
s.ui.Hex(finishedBlob.Hash), s.ui.Size(finishedBlob.Compressed))
s.ui.Info("Blob %s (%s) already exists at %s. Skipping upload.",
s.ui.Hex(finishedBlob.Hash), s.ui.Size(finishedBlob.Compressed), s.ui.Path(destination))
return true, nil
}
s.ui.Begin("Uploading blob %s (%s) to backup destination store.",
s.ui.Hex(finishedBlob.Hash), s.ui.Size(finishedBlob.Compressed))
s.ui.Begin("Uploading blob %s (%s) to %s.",
s.ui.Hex(finishedBlob.Hash), s.ui.Size(finishedBlob.Compressed), s.ui.Path(destination))
progressCallback := s.makeUploadProgressCallback(ctx, finishedBlob, startTime)

View File

@@ -92,8 +92,13 @@ func (v *Vaultik) CreateSnapshot(opts *SnapshotCreateOptions) error {
}
}
// Terminus must obey the --cron invariant: silent on total
// success only. UI.Complete is dropped in cron/quiet mode (that's
// the success path), but if any warnings fired during the run we
// emit the summary via UI.Warning so cron actually delivers
// something for the user to look at.
if v.UI.WarningCount() > 0 {
v.UI.Complete("Finished (with %d warnings).", v.UI.WarningCount())
v.UI.Warning("Finished with %d warning(s) — review the output above.", v.UI.WarningCount())
} else {
v.UI.Complete("Finished successfully.")
}