Skip to content

Commit b41f0a7

Browse files
committed
feat: add space savings display to sietch add operation showing compression efficiency per file and in batch summaries
Signed-off-by: Lorenzo Buitizon <the.keikun@gmail.com>
1 parent 7852795 commit b41f0a7

3 files changed

Lines changed: 73 additions & 8 deletions

File tree

cmd/add.go

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ import (
2222
"github.com/substantialcattle5/sietch/util"
2323
)
2424

25+
// SpaceSavings represents space savings statistics for a file
26+
type SpaceSavings struct {
27+
OriginalSize int64
28+
CompressedSize int64
29+
SpaceSaved int64
30+
SpaceSavedPct float64
31+
}
32+
2533
// addCmd represents the add command
2634
var addCmd = &cobra.Command{
2735
Use: "add <source_path> <destination_path> [source_path2] [destination_path2]...",
@@ -114,6 +122,7 @@ Examples:
114122
// Process each file pair
115123
successCount := 0
116124
var failedFiles []string
125+
var totalSpaceSavings SpaceSavings
117126

118127
// Show initial progress for multiple files
119128
if len(filePairs) > 1 {
@@ -183,16 +192,34 @@ Examples:
183192
continue
184193
}
185194

195+
// Calculate space savings for this file
196+
spaceSavings := calculateSpaceSavings(chunkRefs)
197+
186198
// Success message
187199
if len(filePairs) > 1 {
188-
fmt.Printf("✓ %s (%d chunks)\n", filepath.Base(pair.Source), len(chunkRefs))
200+
fmt.Printf("✓ %s (%d chunks", filepath.Base(pair.Source), len(chunkRefs))
201+
if spaceSavings.SpaceSaved > 0 {
202+
fmt.Printf(", %s saved", util.HumanReadableSize(spaceSavings.SpaceSaved))
203+
}
204+
fmt.Printf(")\n")
189205
} else {
190206
fmt.Printf("✓ File added to vault: %s\n", filepath.Base(pair.Source))
191207
fmt.Printf("✓ %d chunks stored in vault\n", len(chunkRefs))
208+
if spaceSavings.SpaceSaved > 0 {
209+
fmt.Printf("✓ Space saved: %s (%.1f%%)\n",
210+
util.HumanReadableSize(spaceSavings.SpaceSaved),
211+
spaceSavings.SpaceSavedPct)
212+
}
192213
fmt.Printf("✓ Manifest written to .sietch/manifests/%s.yaml\n", filepath.Base(pair.Source))
193214
}
194215

195216
successCount++
217+
218+
// Add to total space savings
219+
fileSavings := calculateSpaceSavings(chunkRefs)
220+
totalSpaceSavings.OriginalSize += fileSavings.OriginalSize
221+
totalSpaceSavings.CompressedSize += fileSavings.CompressedSize
222+
totalSpaceSavings.SpaceSaved += fileSavings.SpaceSaved
196223
}
197224

198225
// Cleanup progress manager
@@ -232,14 +259,21 @@ Examples:
232259

233260
fmt.Printf(" • Compression: %s\n", vaultConfig.Compression)
234261

235-
// Calculate and show space savings if compression is used
236-
if vaultConfig.Compression != "none" {
237-
// TODO: Calculate actual space savings during processing
238-
// For now, show compression info
239-
fmt.Printf(" • Compression: %s (space savings calculated during processing)\n", vaultConfig.Compression)
240-
}
241-
242262
fmt.Printf(" • Chunking: %s (size: %s)\n", vaultConfig.Chunking.Strategy, vaultConfig.Chunking.ChunkSize)
263+
264+
// Show total space savings if compression is used
265+
if vaultConfig.Compression != "none" && totalSpaceSavings.SpaceSaved > 0 {
266+
totalSpaceSavedPct := float64(0)
267+
if totalSpaceSavings.OriginalSize > 0 {
268+
totalSpaceSavedPct = float64(totalSpaceSavings.SpaceSaved) / float64(totalSpaceSavings.OriginalSize) * 100
269+
}
270+
fmt.Printf("\n💾 Total Space Savings:\n")
271+
fmt.Printf(" • Original size: %s\n", util.HumanReadableSize(totalSpaceSavings.OriginalSize))
272+
fmt.Printf(" • Compressed size: %s\n", util.HumanReadableSize(totalSpaceSavings.CompressedSize))
273+
fmt.Printf(" • Space saved: %s (%.1f%%)\n",
274+
util.HumanReadableSize(totalSpaceSavings.SpaceSaved),
275+
totalSpaceSavedPct)
276+
}
243277
}
244278

245279
// Return error only if all files failed
@@ -257,6 +291,35 @@ type FilePair struct {
257291
Destination string
258292
}
259293

294+
// calculateSpaceSavings calculates space savings for a file based on its chunks
295+
func calculateSpaceSavings(chunks []config.ChunkRef) SpaceSavings {
296+
originalSize := int64(0)
297+
compressedSize := int64(0)
298+
299+
for _, chunk := range chunks {
300+
originalSize += chunk.Size
301+
if chunk.CompressedSize > 0 {
302+
compressedSize += chunk.CompressedSize
303+
} else {
304+
// If no compressed size is recorded, use original size
305+
compressedSize += chunk.Size
306+
}
307+
}
308+
309+
spaceSaved := originalSize - compressedSize
310+
var spaceSavedPct float64
311+
if originalSize > 0 {
312+
spaceSavedPct = float64(spaceSaved) / float64(originalSize) * 100
313+
}
314+
315+
return SpaceSavings{
316+
OriginalSize: originalSize,
317+
CompressedSize: compressedSize,
318+
SpaceSaved: spaceSaved,
319+
SpaceSavedPct: spaceSavedPct,
320+
}
321+
}
322+
260323
// parseFileArguments parses command line arguments into source-destination pairs
261324
// Supports two patterns:
262325
// 1. Paired: source1 dest1 source2 dest2 ... (even number of args)

internal/chunk/chunkFile.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ func processFileChunks(ctx context.Context, file *os.File, chunkSize int64, vaul
138138
chunkRef := config.ChunkRef{
139139
Hash: chunkHash,
140140
Size: int64(bytesRead),
141+
CompressedSize: int64(len(compressedData)),
141142
Index: chunkCount - 1, // Convert 1-based chunkCount to 0-based index
142143
Compressed: vaultConfig.Compression != "none",
143144
CompressionType: vaultConfig.Compression,

internal/config/vault.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ type ChunkRef struct {
166166
Hash string `yaml:"hash"` // Hash of chunk content (pre-encryption)
167167
EncryptedHash string `yaml:"encrypted_hash,omitempty"` // Hash of encrypted chunk (filename in storage)
168168
Size int64 `yaml:"size"` // Size of plaintext chunk
169+
CompressedSize int64 `yaml:"compressed_size,omitempty"` // Size after compression but before encryption
169170
EncryptedSize int64 `yaml:"encrypted_size,omitempty"` // Size after encryption
170171
Index int `yaml:"index"` // Position in the file
171172
Deduplicated bool `yaml:"deduplicated,omitempty"` // Whether this chunk was deduplicated

0 commit comments

Comments
 (0)