Refactor: Extract path canonicalization into utils.CanonicalizePath()

Extracts duplicated path canonicalization logic (filepath.Abs + EvalSymlinks)
into a reusable helper function utils.CanonicalizePath() in internal/utils/path.go.

Changes:
- Add internal/utils/path.go with CanonicalizePath() function
- Add comprehensive tests in internal/utils/path_test.go
- Replace inline canonicalization in beads.go:131-140
- Replace inline canonicalization in cmd/bd/main.go:446-454
- Replace inline canonicalization in cmd/bd/nodb.go:25-33

The new helper maintains identical behavior:
1. Converts path to absolute form via filepath.Abs
2. Resolves symlinks via filepath.EvalSymlinks
3. Falls back gracefully on errors (returns absPath if EvalSymlinks fails,
   returns original path if Abs fails)

Fixes bd-efe8

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-11-02 18:51:25 -08:00
parent e5f1e4b971
commit 22756509cc
5 changed files with 145 additions and 28 deletions

View File

@@ -18,6 +18,7 @@ import (
"github.com/steveyegge/beads/internal/storage"
"github.com/steveyegge/beads/internal/storage/sqlite"
"github.com/steveyegge/beads/internal/types"
"github.com/steveyegge/beads/internal/utils"
)
// CanonicalDatabaseName is the required database filename for all beads repositories
@@ -127,16 +128,7 @@ func FindDatabasePath() string {
// 1. Check BEADS_DIR environment variable (preferred)
if beadsDir := os.Getenv("BEADS_DIR"); beadsDir != "" {
// Canonicalize the path to prevent nested .beads directories
var absBeadsDir string
if absPath, err := filepath.Abs(beadsDir); err == nil {
if canonical, err := filepath.EvalSymlinks(absPath); err == nil {
absBeadsDir = canonical
} else {
absBeadsDir = absPath
}
} else {
absBeadsDir = beadsDir
}
absBeadsDir := utils.CanonicalizePath(beadsDir)
// Check for config.json first (single source of truth)
if cfg, err := configfile.Load(absBeadsDir); err == nil && cfg != nil {