Add 'vaultik remote nuke', rename Processing→Backing up, bits/sec rates
remote nuke: new subcommand that deletes every snapshot's metadata and every blob from remote storage, leaving the bucket prefix empty. Requires --force. User-facing 'Processing' is now 'Backing up' everywhere it referred to the chunking/upload phase. Files summary line says 'backed up' instead of 'processed'. ui.Speed now formats bytes/sec input as bits/sec output (bit/s, Kbit/s, Mbit/s, Gbit/s). Network transfer rates are conventionally expressed in bits — the per-blob heartbeat now matches the per-snapshot summary line which has always been bits/sec.
This commit is contained in:
@@ -15,6 +15,31 @@ type PruneOptions struct {
|
||||
JSON bool
|
||||
}
|
||||
|
||||
// NukeRemote deletes every snapshot's metadata and every blob from remote
|
||||
// storage. After this returns successfully the bucket prefix is empty and
|
||||
// the next backup starts from scratch.
|
||||
//
|
||||
// Refuses to run unless force is true. The caller is responsible for
|
||||
// confirming with the user.
|
||||
func (v *Vaultik) NukeRemote(force bool) error {
|
||||
if !force {
|
||||
return fmt.Errorf("nuke requires --force (this deletes ALL remote snapshots and blobs)")
|
||||
}
|
||||
|
||||
v.UI.Begin("Removing all snapshot metadata from backup destination store.")
|
||||
if _, err := v.RemoveAllSnapshots(&RemoveOptions{Force: true, Remote: true}); err != nil {
|
||||
return fmt.Errorf("removing all snapshots: %w", err)
|
||||
}
|
||||
|
||||
v.UI.Begin("Removing all blobs from backup destination store.")
|
||||
if err := v.PruneBlobs(&PruneOptions{Force: true}); err != nil {
|
||||
return fmt.Errorf("pruning blobs: %w", err)
|
||||
}
|
||||
|
||||
v.UI.Complete("Backup destination store is now empty.")
|
||||
return nil
|
||||
}
|
||||
|
||||
// PruneBlobsResult contains the result of a blob prune operation
|
||||
type PruneBlobsResult struct {
|
||||
BlobsFound int `json:"blobs_found"`
|
||||
|
||||
@@ -306,23 +306,13 @@ func (v *Vaultik) finalizeSnapshotMetadata(snapshotID string, stats *snapshotSta
|
||||
return nil
|
||||
}
|
||||
|
||||
// formatUploadSpeed formats bytes uploaded and duration into a human-readable speed string
|
||||
func formatUploadSpeed(bytesUploaded int64, duration time.Duration) string {
|
||||
// uploadSpeed returns the average network upload rate as a colorized
|
||||
// bits/sec string, or "N/A" when there's no usable data.
|
||||
func (v *Vaultik) uploadSpeed(bytesUploaded int64, duration time.Duration) string {
|
||||
if bytesUploaded <= 0 || duration <= 0 {
|
||||
return "N/A"
|
||||
}
|
||||
bytesPerSec := float64(bytesUploaded) / duration.Seconds()
|
||||
bitsPerSec := bytesPerSec * 8
|
||||
switch {
|
||||
case bitsPerSec >= 1e9:
|
||||
return fmt.Sprintf("%.1f Gbit/s", bitsPerSec/1e9)
|
||||
case bitsPerSec >= 1e6:
|
||||
return fmt.Sprintf("%.0f Mbit/s", bitsPerSec/1e6)
|
||||
case bitsPerSec >= 1e3:
|
||||
return fmt.Sprintf("%.0f Kbit/s", bitsPerSec/1e3)
|
||||
default:
|
||||
return fmt.Sprintf("%.0f bit/s", bitsPerSec)
|
||||
return v.UI.Speed(0)
|
||||
}
|
||||
return v.UI.Speed(float64(bytesUploaded) / duration.Seconds())
|
||||
}
|
||||
|
||||
// printSnapshotSummary prints the comprehensive snapshot completion summary
|
||||
@@ -342,7 +332,7 @@ func (v *Vaultik) printSnapshotSummary(snapshotID string, startTime time.Time, s
|
||||
}
|
||||
|
||||
v.UI.Complete("Created snapshot %s.", v.UI.Snapshot(snapshotID))
|
||||
filesMsg := fmt.Sprintf("Files: %s examined, %s processed, %s unchanged",
|
||||
filesMsg := fmt.Sprintf("Files: %s examined, %s backed up, %s unchanged",
|
||||
v.UI.Count(stats.totalFiles),
|
||||
v.UI.Count(totalFilesChanged),
|
||||
v.UI.Count(stats.totalFilesSkipped))
|
||||
@@ -351,7 +341,7 @@ func (v *Vaultik) printSnapshotSummary(snapshotID string, startTime time.Time, s
|
||||
}
|
||||
v.UI.Detail("%s.", filesMsg)
|
||||
|
||||
dataMsg := fmt.Sprintf("Data: %s total (%s processed)",
|
||||
dataMsg := fmt.Sprintf("Data: %s total (%s backed up)",
|
||||
v.UI.Size(totalBytesAll),
|
||||
v.UI.Size(stats.totalBytes))
|
||||
if stats.totalBytesDeleted > 0 {
|
||||
@@ -368,7 +358,7 @@ func (v *Vaultik) printSnapshotSummary(snapshotID string, startTime time.Time, s
|
||||
stats.totalBlobsUploaded,
|
||||
v.UI.Size(stats.totalBytesUploaded),
|
||||
v.UI.Duration(stats.uploadDuration),
|
||||
formatUploadSpeed(stats.totalBytesUploaded, stats.uploadDuration))
|
||||
v.uploadSpeed(stats.totalBytesUploaded, stats.uploadDuration))
|
||||
}
|
||||
v.UI.Detail("Snapshot create duration: %s.", v.UI.Duration(snapshotDuration))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user