Files
beads/internal/storage/factory/factory_dolt.go
obsidian 2cbffca4f3 feat(dolt): implement automatic bootstrap from JSONL on first access
Add automatic Dolt database bootstrapping when JSONL files exist but no
Dolt database is present (cold-start scenario after git clone).

Key features:
- Lock/wait pattern prevents concurrent bootstrap races
- Graceful degradation skips malformed JSONL lines with warnings
- Multi-table ordering: issues → labels → dependencies
- Prefix auto-detection from JSONL content

New files:
- internal/storage/dolt/bootstrap.go - Bootstrap logic
- internal/storage/dolt/bootstrap_test.go - Comprehensive tests

Modified:
- internal/storage/factory/factory_dolt.go - Integration point

Closes: hq-ew1mbr.10

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 01:54:31 -08:00

47 lines
1.4 KiB
Go

//go:build cgo
package factory
import (
"context"
"fmt"
"os"
"path/filepath"
"github.com/steveyegge/beads/internal/configfile"
"github.com/steveyegge/beads/internal/storage"
"github.com/steveyegge/beads/internal/storage/dolt"
)
func init() {
RegisterBackend(configfile.BackendDolt, func(ctx context.Context, path string, opts Options) (storage.Storage, error) {
// Check if bootstrap is needed (JSONL exists but Dolt doesn't)
// Path is the dolt subdirectory, parent is .beads directory
beadsDir := filepath.Dir(path)
bootstrapped, result, err := dolt.Bootstrap(ctx, dolt.BootstrapConfig{
BeadsDir: beadsDir,
DoltPath: path,
LockTimeout: opts.LockTimeout,
})
if err != nil {
return nil, fmt.Errorf("bootstrap failed: %w", err)
}
if bootstrapped && result != nil {
// Report bootstrap results
fmt.Fprintf(os.Stderr, "Bootstrapping Dolt from JSONL...\n")
if len(result.ParseErrors) > 0 {
fmt.Fprintf(os.Stderr, " Skipped %d malformed lines (see above for details)\n", len(result.ParseErrors))
}
fmt.Fprintf(os.Stderr, " Imported %d issues", result.IssuesImported)
if result.IssuesSkipped > 0 {
fmt.Fprintf(os.Stderr, ", skipped %d duplicates", result.IssuesSkipped)
}
fmt.Fprintf(os.Stderr, "\n Dolt database ready\n")
}
return dolt.New(ctx, &dolt.Config{Path: path, ReadOnly: opts.ReadOnly})
})
}