Finish the lint remediation: script/cibuild exits 0 (closes #61) #77
30
TODO.md
30
TODO.md
@@ -14,16 +14,36 @@ pre-1.0
|
||||
|
||||
# Next Step
|
||||
|
||||
Reconcile the uncommitted ARCHITECTURE.md edits on main: finish and
|
||||
commit, or revert.
|
||||
Triage the stale remote branches (issue #71): for each, merge the work
|
||||
or delete the branch.
|
||||
|
||||
# Completed Steps
|
||||
|
||||
- 2026-08-09: Finished the lint remediation under the canonical
|
||||
`.golangci.yml` (issue #61, which also unblocks issue #59). The
|
||||
remaining findings were fixed behavior-preservingly: `wsl_v5`
|
||||
whitespace, `sqlclosecheck`, and `prealloc`. The `sqlclosecheck` sites
|
||||
now close `sql.Rows` in a deferred closure instead of via the
|
||||
`CloseRows` helper, which the linter could not see through. Only the
|
||||
`revive` package-name findings remain suppressed, with per-site
|
||||
`//nolint` directives; the package-rename question behind them is
|
||||
tracked in issue #76. Verified with `script/cibuild`, which exits 0 —
|
||||
that is the only trustworthy gate, because `script/lint` runs whatever
|
||||
`golangci-lint` happens to be on `PATH` rather than the pinned
|
||||
v2.12.2 that CI and the `Dockerfile` use, so `make check` can report
|
||||
green on findings CI still fails. That tooling gap is tracked in issue
|
||||
#78.
|
||||
- 2026-08-09: The earlier next step "reconcile the uncommitted
|
||||
`ARCHITECTURE.md` edits on `main`" needed no work: the working tree is
|
||||
clean and `ARCHITECTURE.md` is committed on `main`.
|
||||
- 2026-08-07: Updated golangci-lint to v2.12.2 everywhere it is pinned
|
||||
(`Dockerfile` lint stage, `Makefile` deps target), replaced
|
||||
`.golangci.yml` with the canonical config (v2 schema, `default: all`),
|
||||
and remediated all lint findings it surfaced (issue #61):
|
||||
behavior-preserving fixes across every package, `make check` green.
|
||||
and remediated the bulk of the lint findings it surfaced (issue #61):
|
||||
behavior-preserving fixes across every package, 2,990 findings down to
|
||||
80. `make test` and `make fmt-check` were green at that point but
|
||||
`make lint` was still red; the commit message claiming `make check`
|
||||
was green was wrong.
|
||||
- 2026-08-07: Added the standard `.golangci.yml` and `.editorconfig`
|
||||
(issue #59); lint findings under the new config are tracked in issue
|
||||
#61. `script/bootstrap` now installs sqlite3 (needed by tests).
|
||||
@@ -49,6 +69,4 @@ commit, or revert.
|
||||
|
||||
# Future Steps
|
||||
|
||||
- Review stale local branches (add-godoc-to-cli-package,
|
||||
feature/pluggable-storage-backend) and merge or delete them.
|
||||
- Define remaining scope for a first tagged release and cut v0.1.0.
|
||||
|
||||
@@ -16,6 +16,7 @@ func main() {
|
||||
if err != nil {
|
||||
panic("could not create CPU profile: " + err.Error())
|
||||
}
|
||||
|
||||
defer func() { _ = f.Close() }()
|
||||
|
||||
err = pprof.StartCPUProfile(f)
|
||||
@@ -33,6 +34,7 @@ func main() {
|
||||
if err != nil {
|
||||
panic("could not create memory profile: " + err.Error())
|
||||
}
|
||||
|
||||
defer func() { _ = f.Close() }()
|
||||
|
||||
runtime.GC() // get up-to-date statistics
|
||||
|
||||
@@ -64,6 +64,7 @@ func CompressStream(
|
||||
}
|
||||
|
||||
closed := false
|
||||
|
||||
defer func() {
|
||||
if !closed {
|
||||
_ = w.Close()
|
||||
|
||||
@@ -163,6 +163,7 @@ func (c *Chunker) ChunkFile(path string) ([]Chunk, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("opening file: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := file.Close()
|
||||
if err != nil && err.Error() != "invalid argument" {
|
||||
|
||||
@@ -53,7 +53,7 @@ func TestChunkerLargeFileMultipleChunks(t *testing.T) {
|
||||
}
|
||||
|
||||
// Verify chunks reconstruct original data
|
||||
var reconstructed []byte
|
||||
reconstructed := make([]byte, 0, len(data))
|
||||
for _, chunk := range chunks {
|
||||
reconstructed = append(reconstructed, chunk.Data...)
|
||||
}
|
||||
|
||||
@@ -157,6 +157,7 @@ func RunApp(ctx context.Context, app *fx.App) error {
|
||||
|
||||
// Handle shutdown
|
||||
shutdownComplete := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(shutdownComplete)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package crypto provides thread-safe age encryption and decryption
|
||||
// helpers used to protect blob and metadata content.
|
||||
package crypto
|
||||
package crypto //nolint:revive,nolintlint // stdlib crypto unused; see #76
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
@@ -57,7 +57,13 @@ func (r *BlobChunkRepository) GetByBlobID(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying blob chunks: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var blobChunks []*BlobChunk
|
||||
|
||||
|
||||
@@ -82,7 +82,13 @@ func (r *BlobRepository) GetAll(ctx context.Context) (map[string]*Blob, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying blobs: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
out := make(map[string]*Blob)
|
||||
|
||||
|
||||
@@ -60,7 +60,13 @@ func (r *ChunkFileRepository) GetByChunkHash(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying chunk files: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return r.scanChunkFiles(rows)
|
||||
}
|
||||
@@ -80,7 +86,13 @@ func (r *ChunkFileRepository) GetByFilePath(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying chunk files: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return r.scanChunkFiles(rows)
|
||||
}
|
||||
@@ -99,7 +111,13 @@ func (r *ChunkFileRepository) GetByFileID(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying chunk files: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return r.scanChunkFiles(rows)
|
||||
}
|
||||
|
||||
@@ -106,7 +106,13 @@ func (r *ChunkRepository) GetByHashes(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying chunks: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var chunks []*Chunk
|
||||
|
||||
@@ -145,7 +151,13 @@ func (r *ChunkRepository) ListUnpacked(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying unpacked chunks: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var chunks []*Chunk
|
||||
|
||||
|
||||
@@ -17,7 +17,13 @@ func (r *ChunkRepository) List(ctx context.Context) ([]*Chunk, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying chunks: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var chunks []*Chunk
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ func TestDatabase(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create database: %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := db.Close()
|
||||
if err != nil {
|
||||
@@ -73,6 +74,7 @@ func TestDatabaseConcurrentAccess(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create database: %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := db.Close()
|
||||
if err != nil {
|
||||
@@ -182,6 +184,7 @@ func TestApplyMigrations_Idempotent(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open database: %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := conn.Close()
|
||||
if err != nil {
|
||||
@@ -239,6 +242,7 @@ func TestBootstrapMigrationsTable_FreshDatabase(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open database: %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := conn.Close()
|
||||
if err != nil {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
@@ -11,11 +10,3 @@ func Fatalf(format string, args ...any) {
|
||||
fmt.Fprintf(os.Stderr, "FATAL: "+format+"\n", args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// CloseRows closes rows and exits on error
|
||||
func CloseRows(rows *sql.Rows) {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,13 @@ func (r *FileChunkRepository) GetByPath(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying file chunks: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return r.scanFileChunks(rows)
|
||||
}
|
||||
@@ -81,7 +87,13 @@ func (r *FileChunkRepository) GetByFileID(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying file chunks: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return r.scanFileChunks(rows)
|
||||
}
|
||||
@@ -104,7 +116,13 @@ func (r *FileChunkRepository) GetByPathTx(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying file chunks: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
fileChunks, err := r.scanFileChunks(rows)
|
||||
LogSQL("GetByPathTx", "Complete", path, "count", len(fileChunks))
|
||||
|
||||
@@ -168,7 +168,13 @@ func (r *FileRepository) ListModifiedSince(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying files: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var files []*File
|
||||
|
||||
@@ -238,7 +244,13 @@ func (r *FileRepository) ListByPrefix(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying files: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var files []*File
|
||||
|
||||
@@ -266,7 +278,13 @@ func (r *FileRepository) ListAll(ctx context.Context) ([]*File, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying files: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var files []*File
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ func logSnapshotFileIDs(t *testing.T, db *DB) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
|
||||
@@ -223,7 +223,13 @@ func (r *SnapshotRepository) ListRecent(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying snapshots: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return r.scanSnapshotRows(rows)
|
||||
}
|
||||
@@ -437,7 +443,13 @@ func (r *SnapshotRepository) GetBlobHashes(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying blob hashes: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var blobs []string
|
||||
|
||||
@@ -561,7 +573,13 @@ func (r *SnapshotRepository) GetIncompleteSnapshots(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying incomplete snapshots: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return r.scanSnapshotRows(rows)
|
||||
}
|
||||
@@ -583,7 +601,13 @@ func (r *SnapshotRepository) GetIncompleteByHostname(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying incomplete snapshots: %w", err)
|
||||
}
|
||||
defer CloseRows(rows)
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
Fatalf("failed to close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var snapshots []*Snapshot
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ func (r *UploadRepository) GetRecentUploads(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
if err != nil {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package log provides the application-wide structured logger: slog
|
||||
// with a colorized TTY handler on terminals and JSON output otherwise.
|
||||
package log
|
||||
package log //nolint:revive,nolintlint // stdlib log unused here; see #76
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -69,7 +69,7 @@ func Initialize(cfg Config) {
|
||||
Level: level,
|
||||
}
|
||||
|
||||
// Check if stdout is a TTY
|
||||
// Check if stdout is a TTY.
|
||||
if term.IsTerminal(int(os.Stdout.Fd())) {
|
||||
// Use colorized TTY handler
|
||||
logger = slog.New(NewTTYHandler(os.Stdout, opts))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package log
|
||||
package log //nolint:revive,nolintlint // stdlib log unused here; see #76
|
||||
|
||||
import (
|
||||
"go.uber.org/fx"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package log
|
||||
package log //nolint:revive,nolintlint // stdlib log unused here; see #76
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
@@ -48,6 +48,7 @@ func TestAcquireBlocksSecondInstance(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotNil(t, lock1)
|
||||
|
||||
defer func() { _ = lock1.Release() }()
|
||||
|
||||
// Try to acquire second lock - should fail
|
||||
@@ -72,6 +73,7 @@ func TestAcquireWithStaleLock(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotNil(t, lock)
|
||||
|
||||
defer func() { _ = lock.Release() }()
|
||||
|
||||
// Verify our PID is now in the file
|
||||
@@ -117,6 +119,7 @@ func TestAcquireCreatesDirectory(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotNil(t, lock)
|
||||
|
||||
defer func() { _ = lock.Release() }()
|
||||
|
||||
// Verify directory was created
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
//nolint:paralleltest // test servers share a fixed localhost port
|
||||
func TestClient(t *testing.T) {
|
||||
ts := NewTestServer(t)
|
||||
|
||||
defer func() {
|
||||
err := ts.Cleanup()
|
||||
if err != nil {
|
||||
@@ -58,6 +59,7 @@ func verifyPutGetHead(
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get object: %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := reader.Close()
|
||||
if err != nil {
|
||||
|
||||
@@ -147,6 +147,7 @@ func (ts *TestServer) Client() *s3.Client {
|
||||
//nolint:paralleltest // test servers share a fixed localhost port
|
||||
func TestBasicS3Operations(t *testing.T) {
|
||||
ts := NewTestServer(t)
|
||||
|
||||
defer func() {
|
||||
err := ts.Cleanup()
|
||||
if err != nil {
|
||||
@@ -179,6 +180,7 @@ func TestBasicS3Operations(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get object: %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := result.Body.Close()
|
||||
if err != nil {
|
||||
@@ -202,6 +204,7 @@ func TestBasicS3Operations(t *testing.T) {
|
||||
//nolint:paralleltest // test servers share a fixed localhost port
|
||||
func TestBlobOperations(t *testing.T) {
|
||||
ts := NewTestServer(t)
|
||||
|
||||
defer func() {
|
||||
err := ts.Cleanup()
|
||||
if err != nil {
|
||||
@@ -268,6 +271,7 @@ func TestBlobOperations(t *testing.T) {
|
||||
//nolint:paralleltest // test servers share a fixed localhost port
|
||||
func TestMetadataOperations(t *testing.T) {
|
||||
ts := NewTestServer(t)
|
||||
|
||||
defer func() {
|
||||
err := ts.Cleanup()
|
||||
if err != nil {
|
||||
|
||||
@@ -461,6 +461,7 @@ func (b *BackupEngine) backupOneFile(
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := f.Close()
|
||||
if err != nil {
|
||||
|
||||
@@ -75,6 +75,7 @@ func TestFileContentChange(t *testing.T) {
|
||||
db, err := database.NewTestDB()
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() {
|
||||
err := db.Close()
|
||||
if err != nil {
|
||||
@@ -165,6 +166,7 @@ func TestMultipleFileChanges(t *testing.T) {
|
||||
db, err := database.NewTestDB()
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() {
|
||||
err := db.Close()
|
||||
if err != nil {
|
||||
|
||||
@@ -127,6 +127,7 @@ func NewProgressReporter() *ProgressReporter {
|
||||
// Start begins the progress reporting
|
||||
func (pr *ProgressReporter) Start() {
|
||||
pr.wg.Add(1)
|
||||
|
||||
go pr.run()
|
||||
|
||||
// Print initial multi-line status
|
||||
|
||||
@@ -624,11 +624,12 @@ func (s *Scanner) collectBatchFlushData(
|
||||
|
||||
collectStart := time.Now()
|
||||
|
||||
var (
|
||||
allFileChunks []database.FileChunk
|
||||
allChunkFiles []database.ChunkFile
|
||||
)
|
||||
|
||||
// A pending file contributes one mapping of each kind per chunk, and
|
||||
// an empty file contributes none, so the file count is only a rough
|
||||
// starting capacity for the mapping slices; append grows them as
|
||||
// needed. It is exact for the file and file-ID slices.
|
||||
allFileChunks := make([]database.FileChunk, 0, len(canFlush))
|
||||
allChunkFiles := make([]database.ChunkFile, 0, len(canFlush))
|
||||
allFileIDs := make([]types.FileID, 0, len(canFlush))
|
||||
allFiles := make([]*database.File, 0, len(canFlush))
|
||||
|
||||
@@ -1673,6 +1674,7 @@ func (s *Scanner) processFileStreaming(
|
||||
if err != nil {
|
||||
return fmt.Errorf("opening file: %w", wrapPermissionError(fileToProcess.Path, err))
|
||||
}
|
||||
|
||||
defer func() { _ = file.Close() }()
|
||||
|
||||
var chunks []streamingChunkInfo
|
||||
|
||||
@@ -164,6 +164,7 @@ func TestScannerSimpleDirectory(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create test database: %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := db.Close()
|
||||
if err != nil {
|
||||
@@ -241,6 +242,7 @@ func TestScannerLargeFile(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create test database: %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := db.Close()
|
||||
if err != nil {
|
||||
|
||||
@@ -259,6 +259,7 @@ func (sm *SnapshotManager) ExportSnapshotMetadata(
|
||||
}
|
||||
|
||||
log.Debug("Created temporary directory", "path", tempDir)
|
||||
|
||||
defer func() {
|
||||
log.Debug("Cleaning up temporary directory", "path", tempDir)
|
||||
|
||||
@@ -555,6 +556,7 @@ func (sm *SnapshotManager) cleanSnapshotDB(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("opening temp database: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := db.Close()
|
||||
if err != nil {
|
||||
@@ -567,6 +569,7 @@ func (sm *SnapshotManager) cleanSnapshotDB(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("beginning transaction: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
rbErr := tx.Rollback()
|
||||
if rbErr != nil && !errors.Is(rbErr, sql.ErrTxDone) {
|
||||
@@ -685,6 +688,7 @@ func (sm *SnapshotManager) compressFile(inputPath, outputPath string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("opening input file: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := input.Close()
|
||||
if err != nil {
|
||||
@@ -696,6 +700,7 @@ func (sm *SnapshotManager) compressFile(inputPath, outputPath string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating output file: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := output.Close()
|
||||
if err != nil {
|
||||
@@ -714,6 +719,7 @@ func (sm *SnapshotManager) compressFile(inputPath, outputPath string) error {
|
||||
|
||||
// Track if writer has been closed to avoid double-close
|
||||
writerClosed := false
|
||||
|
||||
defer func() {
|
||||
if !writerClosed {
|
||||
err := writer.Close()
|
||||
@@ -749,6 +755,7 @@ func (sm *SnapshotManager) copyFile(src, dst string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
log.Debug("Closing source file", "path", src)
|
||||
|
||||
@@ -764,6 +771,7 @@ func (sm *SnapshotManager) copyFile(src, dst string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
log.Debug("Closing destination file", "path", dst)
|
||||
|
||||
@@ -794,6 +802,7 @@ func (sm *SnapshotManager) generateBlobManifest(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("opening database: %w", err)
|
||||
}
|
||||
|
||||
defer func() { _ = db.Close() }()
|
||||
|
||||
// Create repositories to access the data
|
||||
|
||||
@@ -25,12 +25,14 @@ func copyFile(fs afero.Fs, src, dst string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() { _ = sourceFile.Close() }()
|
||||
|
||||
destFile, err := fs.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() { _ = destFile.Close() }()
|
||||
|
||||
_, err = io.Copy(destFile, sourceFile)
|
||||
@@ -53,6 +55,7 @@ func verifyCleanedDB(
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open cleaned database: %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := cleanedDB.Close()
|
||||
if err != nil {
|
||||
|
||||
@@ -62,6 +62,7 @@ func (f *FileStorer) Put(_ context.Context, key string, data io.Reader) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating file: %w", err)
|
||||
}
|
||||
|
||||
defer func() { _ = file.Close() }()
|
||||
|
||||
_, err = io.Copy(file, data)
|
||||
@@ -91,6 +92,7 @@ func (f *FileStorer) PutWithProgress(
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating file: %w", err)
|
||||
}
|
||||
|
||||
defer func() { _ = file.Close() }()
|
||||
|
||||
// Wrap with progress tracking
|
||||
@@ -209,6 +211,7 @@ func (f *FileStorer) List(ctx context.Context, prefix string) ([]string, error)
|
||||
// ListStream returns a channel of ObjectInfo for large result sets.
|
||||
func (f *FileStorer) ListStream(ctx context.Context, prefix string) <-chan ObjectInfo {
|
||||
ch := make(chan ObjectInfo)
|
||||
|
||||
go func() {
|
||||
defer close(ch)
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ func (s *S3Storer) List(ctx context.Context, prefix string) ([]string, error) {
|
||||
// ListStream returns a channel of ObjectInfo for large result sets.
|
||||
func (s *S3Storer) ListStream(ctx context.Context, prefix string) <-chan ObjectInfo {
|
||||
ch := make(chan ObjectInfo)
|
||||
|
||||
go func() {
|
||||
defer close(ch)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// vaultik codebase. Using distinct types for IDs, hashes, paths, and
|
||||
// credentials prevents accidental mixing of semantically different values
|
||||
// that happen to share the same underlying type.
|
||||
package types
|
||||
package types //nolint:revive,nolintlint // rename decision tracked in #76
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
|
||||
@@ -238,6 +238,7 @@ func (c *blobDiskCache) ReadAt(key string, offset, length int64) ([]byte, error)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func() { _ = f.Close() }()
|
||||
|
||||
buf := make([]byte, length)
|
||||
|
||||
@@ -14,6 +14,7 @@ func TestBlobDiskCache_BasicGetPut(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() { _ = cache.Close() }()
|
||||
|
||||
data := []byte("hello world")
|
||||
@@ -79,6 +80,7 @@ func TestBlobDiskCache_OversizedEntryRejected(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() { _ = cache.Close() }()
|
||||
|
||||
data := make([]byte, 200)
|
||||
@@ -100,6 +102,7 @@ func TestBlobDiskCache_UpdateInPlace(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() { _ = cache.Close() }()
|
||||
|
||||
err = cache.Put("key1", []byte("v1"))
|
||||
@@ -137,6 +140,7 @@ func TestBlobDiskCache_ReadAt(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() { _ = cache.Close() }()
|
||||
|
||||
data := make([]byte, 1024)
|
||||
@@ -197,6 +201,7 @@ func TestBlobDiskCache_LRUOrder(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() { _ = cache.Close() }()
|
||||
|
||||
d := make([]byte, 100)
|
||||
|
||||
@@ -134,6 +134,7 @@ func (m *MockStorer) ListStream(
|
||||
_ context.Context, prefix string,
|
||||
) <-chan storage.ObjectInfo {
|
||||
ch := make(chan storage.ObjectInfo)
|
||||
|
||||
go func() {
|
||||
defer close(ch)
|
||||
|
||||
@@ -326,6 +327,7 @@ func TestEndToEndBackup(t *testing.T) {
|
||||
db, err := database.New(ctx, ":memory:")
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() {
|
||||
err := db.Close()
|
||||
if err != nil {
|
||||
@@ -411,6 +413,7 @@ func TestBackupAndVerify(t *testing.T) {
|
||||
db, err := database.New(ctx, ":memory:")
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() {
|
||||
err := db.Close()
|
||||
if err != nil {
|
||||
@@ -968,6 +971,7 @@ func TestDedupOnlySnapshotRestores(t *testing.T) {
|
||||
|
||||
env := setupDedupBackupEnv(
|
||||
ctx, t, fs, storeDir, dbPath, chunkSize, maxBlobSize)
|
||||
|
||||
defer func() { _ = env.db.Close() }()
|
||||
|
||||
cfg, storer, repos, sm := env.cfg, env.storer, env.repos, env.sm
|
||||
|
||||
@@ -590,6 +590,7 @@ func (v *Vaultik) downloadSnapshotDB(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("downloading %s: %w", dbKey, err)
|
||||
}
|
||||
|
||||
defer func() { _ = reader.Close() }()
|
||||
|
||||
// Read all data
|
||||
@@ -606,6 +607,7 @@ func (v *Vaultik) downloadSnapshotDB(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating decryption reader: %w", err)
|
||||
}
|
||||
|
||||
defer func() { _ = blobReader.Close() }()
|
||||
|
||||
// Read the binary SQLite database
|
||||
@@ -1115,6 +1117,7 @@ func (v *Vaultik) verifyFile(
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("opening file: %w", err)
|
||||
}
|
||||
|
||||
defer func() { _ = f.Close() }()
|
||||
|
||||
// Verify each chunk
|
||||
|
||||
@@ -110,6 +110,7 @@ func (s *restoreSweeper) blobStillNeeded(blobHash string) (bool, error) {
|
||||
if err != nil {
|
||||
return true, fmt.Errorf("querying referencing files: %w", err)
|
||||
}
|
||||
|
||||
defer func() { _ = rows.Close() }()
|
||||
|
||||
for rows.Next() {
|
||||
|
||||
@@ -1130,6 +1130,7 @@ func (v *Vaultik) downloadManifestByKey(remoteKey string) (*snapshot.Manifest, e
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func() { _ = reader.Close() }()
|
||||
|
||||
manifest, err := snapshot.DecodeManifest(reader)
|
||||
|
||||
@@ -96,6 +96,7 @@ func (v *Vaultik) RunDeepVerify(snapshotID string, opts *VerifyOptions) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if tempDB != nil {
|
||||
_ = tempDB.Close()
|
||||
@@ -343,6 +344,7 @@ func (v *Vaultik) verifyBlob(blobInfo snapshot.BlobInfo, db *sql.DB) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to download: %w", err)
|
||||
}
|
||||
|
||||
defer func() { _ = reader.Close() }()
|
||||
|
||||
// Get decryptor
|
||||
|
||||
Reference in New Issue
Block a user