From d77ac18aaa361629d739782ecf85d709a4a1a04e Mon Sep 17 00:00:00 2001 From: clawbot Date: Thu, 19 Feb 2026 23:51:53 -0800 Subject: [PATCH] fix: add missing printfStdout, printlnStdout, scanlnStdin, FetchBlob, and FetchAndDecryptBlob methods These methods were referenced in main but never defined, causing compilation failures. They were introduced by merges that assumed dependent PRs were already merged. --- internal/vaultik/restore.go | 47 ++++++++++++++++++++++++++++++++++++ internal/vaultik/snapshot.go | 2 +- internal/vaultik/vaultik.go | 28 +++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/internal/vaultik/restore.go b/internal/vaultik/restore.go index 015c533..aa00a27 100644 --- a/internal/vaultik/restore.go +++ b/internal/vaultik/restore.go @@ -473,6 +473,53 @@ func (v *Vaultik) restoreRegularFile( return nil } +// BlobFetchResult holds the result of fetching and decrypting a blob. +type BlobFetchResult struct { + Data []byte + CompressedSize int64 +} + +// FetchAndDecryptBlob downloads a blob from storage, decrypts and decompresses it. +func (v *Vaultik) FetchAndDecryptBlob(ctx context.Context, blobHash string, expectedSize int64, identity age.Identity) (*BlobFetchResult, error) { + // Construct blob path with sharding + blobPath := fmt.Sprintf("blobs/%s/%s/%s", blobHash[:2], blobHash[2:4], blobHash) + + reader, err := v.Storage.Get(ctx, blobPath) + if err != nil { + return nil, fmt.Errorf("downloading blob: %w", err) + } + defer func() { _ = reader.Close() }() + + // Read encrypted data + encryptedData, err := io.ReadAll(reader) + if err != nil { + return nil, fmt.Errorf("reading blob data: %w", err) + } + + // Decrypt and decompress + blobReader, err := blobgen.NewReader(bytes.NewReader(encryptedData), identity) + if err != nil { + return nil, fmt.Errorf("creating decryption reader: %w", err) + } + defer func() { _ = blobReader.Close() }() + + data, err := io.ReadAll(blobReader) + if err != nil { + return nil, fmt.Errorf("decrypting blob: %w", err) + } + + log.Debug("Downloaded and decrypted blob", + "hash", blobHash[:16], + "encrypted_size", humanize.Bytes(uint64(len(encryptedData))), + "decrypted_size", humanize.Bytes(uint64(len(data))), + ) + + return &BlobFetchResult{ + Data: data, + CompressedSize: int64(len(encryptedData)), + }, nil +} + // downloadBlob downloads and decrypts a blob func (v *Vaultik) downloadBlob(ctx context.Context, blobHash string, expectedSize int64, identity age.Identity) ([]byte, error) { result, err := v.FetchAndDecryptBlob(ctx, blobHash, expectedSize, identity) diff --git a/internal/vaultik/snapshot.go b/internal/vaultik/snapshot.go index 39f4cc8..a6e498b 100644 --- a/internal/vaultik/snapshot.go +++ b/internal/vaultik/snapshot.go @@ -4,8 +4,8 @@ import ( "encoding/json" "fmt" "os" - "regexp" "path/filepath" + "regexp" "sort" "strings" "text/tabwriter" diff --git a/internal/vaultik/vaultik.go b/internal/vaultik/vaultik.go index 4ce6535..7fe5a3b 100644 --- a/internal/vaultik/vaultik.go +++ b/internal/vaultik/vaultik.go @@ -135,6 +135,34 @@ func (v *Vaultik) Outputf(format string, args ...any) { _, _ = fmt.Fprintf(v.Stdout, format, args...) } +// printfStdout writes formatted output to stdout. +func (v *Vaultik) printfStdout(format string, args ...any) { + _, _ = fmt.Fprintf(v.Stdout, format, args...) +} + +// printlnStdout writes a line to stdout. +func (v *Vaultik) printlnStdout(args ...any) { + _, _ = fmt.Fprintln(v.Stdout, args...) +} + +// scanlnStdin reads a line from stdin into the provided string pointer. +func (v *Vaultik) scanlnStdin(s *string) error { + _, err := fmt.Fscanln(v.Stdin, s) + return err +} + +// FetchBlob downloads a blob from storage and returns a reader for the encrypted data. +func (v *Vaultik) FetchBlob(ctx context.Context, blobHash string, expectedSize int64) (io.ReadCloser, int64, error) { + blobPath := fmt.Sprintf("blobs/%s/%s/%s", blobHash[:2], blobHash[2:4], blobHash) + + reader, err := v.Storage.Get(ctx, blobPath) + if err != nil { + return nil, 0, fmt.Errorf("downloading blob: %w", err) + } + + return reader, expectedSize, nil +} + // TestVaultik wraps a Vaultik with captured stdout/stderr for testing type TestVaultik struct { *Vaultik