Files
bsdaily/internal/bsdaily/snapshot.go
sneak 72d052eac3
Some checks are pending
check / check (pull_request) Blocked by required conditions
Update golangci-lint to v2.12.2 with canonical config
Add the canonical .golangci.yml (v2 layout, default: all with the
standard disable list) and pin golangci-lint v2.12.2 in the Makefile
deps target using the v2 module path, replacing the @latest install on
the old v1 path. The Dockerfile lint stage already pinned the v2.12.2
alpine image by digest and is unchanged.

Fix all issues surfaced by the strict config:

- err113: introduce wrapped static sentinel errors
- gocognit/funlen/nestif: split ExtractDay, Run, DumpAndCompress,
  VerifyOutput, and the CLI flag parsing into smaller helpers
- noctx: use ExecContext/QueryContext/BeginTx and CommandContext
- noinlineerr: replace inline if-err assignments with plain ones
- wsl_v5/nlreturn: add required blank lines
- lll: wrap long lines and SQL strings
- gosec: filepath.Clean on file open/create; bounded uint64
  conversion in CheckFreeSpace; named output dir permission constant
- mnd: use unix.FADV_* constants and named size constants
- revive: add package and exported symbol comments
- testpackage/paralleltest: move smoke test to bsdaily_test with
  t.Parallel()
- nonamedreturns: drop non-error named returns

The remaining nolint directives (gosec subprocess launches with
internal paths, unqueryvet full-row SELECT * copies whose schema is
defined by the source database) are each justified inline.
2026-08-07 16:59:29 +00:00

73 lines
1.5 KiB
Go

package bsdaily
import (
"errors"
"fmt"
"log/slog"
"os"
"path/filepath"
"sort"
"time"
)
var errNoSnapshots = errors.New("no daily snapshots found")
// FindLatestDailySnapshot locates the newest daily ZFS snapshot that
// contains the firehose database and returns its directory and date.
func FindLatestDailySnapshot() (string, time.Time, error) {
entries, err := os.ReadDir(SnapshotBase)
if err != nil {
return "", time.Time{}, fmt.Errorf(
"reading snapshot directory %s: %w", SnapshotBase, err)
}
type snapshot struct {
name string
date time.Time
}
var snapshots []snapshot
for _, e := range entries {
if !e.IsDir() {
continue
}
m := snapshotPattern.FindStringSubmatch(e.Name())
if m == nil {
continue
}
d, perr := time.Parse("2006-01-02", m[1])
if perr != nil {
slog.Warn("skipping snapshot with unparseable date",
"name", e.Name(), "error", perr)
continue
}
snapshots = append(snapshots, snapshot{name: e.Name(), date: d})
}
if len(snapshots) == 0 {
return "", time.Time{}, fmt.Errorf("%w in %s", errNoSnapshots, SnapshotBase)
}
sort.Slice(snapshots, func(i, j int) bool {
return snapshots[i].date.After(snapshots[j].date)
})
latest := snapshots[0]
dir := filepath.Join(SnapshotBase, latest.name)
dbPath := filepath.Join(dir, DBFilename)
_, err = os.Stat(dbPath)
if err != nil {
return "", time.Time{}, fmt.Errorf(
"database not found in snapshot %s: %w", dir, err)
}
return dir, latest.date, nil
}