mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
863e0a4e24
Signed-off-by: phernandez <paul@basicmachines.co> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
106 lines
4.3 KiB
Python
106 lines
4.3 KiB
Python
"""Database management commands."""
|
|
|
|
from pathlib import Path
|
|
|
|
import typer
|
|
from loguru import logger
|
|
from rich.console import Console
|
|
from sqlalchemy.exc import OperationalError
|
|
|
|
from basic_memory import db
|
|
from basic_memory.cli.app import app
|
|
from basic_memory.cli.commands.command_utils import run_with_cleanup
|
|
from basic_memory.config import ConfigManager
|
|
from basic_memory.repository import ProjectRepository
|
|
from basic_memory.services.initialization import reconcile_projects_with_config
|
|
from basic_memory.sync.sync_service import get_sync_service
|
|
|
|
console = Console()
|
|
|
|
|
|
async def _reindex_projects(app_config):
|
|
"""Reindex all projects in a single async context.
|
|
|
|
This ensures all database operations use the same event loop,
|
|
and proper cleanup happens when the function completes.
|
|
"""
|
|
try:
|
|
await reconcile_projects_with_config(app_config)
|
|
|
|
# Get database session (migrations already run if needed)
|
|
_, session_maker = await db.get_or_create_db(
|
|
db_path=app_config.database_path,
|
|
db_type=db.DatabaseType.FILESYSTEM,
|
|
)
|
|
project_repository = ProjectRepository(session_maker)
|
|
projects = await project_repository.get_active_projects()
|
|
|
|
for project in projects:
|
|
console.print(f" Indexing [cyan]{project.name}[/cyan]...")
|
|
logger.info(f"Starting sync for project: {project.name}")
|
|
sync_service = await get_sync_service(project)
|
|
sync_dir = Path(project.path)
|
|
await sync_service.sync(sync_dir, project_name=project.name)
|
|
logger.info(f"Sync completed for project: {project.name}")
|
|
finally:
|
|
# Clean up database connections before event loop closes
|
|
await db.shutdown_db()
|
|
|
|
|
|
@app.command()
|
|
def reset(
|
|
reindex: bool = typer.Option(False, "--reindex", help="Rebuild db index from filesystem"),
|
|
): # pragma: no cover
|
|
"""Reset database (drop all tables and recreate)."""
|
|
console.print(
|
|
"[yellow]Note:[/yellow] This only deletes the index database. "
|
|
"Your markdown note files will not be affected.\n"
|
|
"Use [green]bm reset --reindex[/green] to automatically rebuild the index afterward."
|
|
)
|
|
if typer.confirm("Reset the database index?"):
|
|
logger.info("Resetting database...")
|
|
config_manager = ConfigManager()
|
|
app_config = config_manager.config
|
|
# Get database path
|
|
db_path = app_config.app_database_path
|
|
|
|
# Delete the database file and WAL files if they exist
|
|
for suffix in ["", "-shm", "-wal"]:
|
|
path = db_path.parent / f"{db_path.name}{suffix}"
|
|
if path.exists():
|
|
try:
|
|
path.unlink()
|
|
logger.info(f"Deleted: {path}")
|
|
except OSError as e:
|
|
console.print(
|
|
f"[red]Error:[/red] Cannot delete {path.name}: {e}\n"
|
|
"The database may be in use by another process (e.g., MCP server).\n"
|
|
"Please close Claude Desktop or any other Basic Memory clients and try again."
|
|
)
|
|
raise typer.Exit(1)
|
|
|
|
# Create a new empty database (preserves project configuration)
|
|
try:
|
|
run_with_cleanup(db.run_migrations(app_config))
|
|
except OperationalError as e:
|
|
if "disk I/O error" in str(e) or "database is locked" in str(e):
|
|
console.print(
|
|
"[red]Error:[/red] Cannot access database. "
|
|
"It may be in use by another process (e.g., MCP server).\n"
|
|
"Please close Claude Desktop or any other Basic Memory clients and try again."
|
|
)
|
|
raise typer.Exit(1)
|
|
raise
|
|
console.print("[green]Database reset complete[/green]")
|
|
|
|
if reindex:
|
|
projects = list(app_config.projects)
|
|
if not projects:
|
|
console.print("[yellow]No projects configured. Skipping reindex.[/yellow]")
|
|
else:
|
|
console.print(f"Rebuilding search index for {len(projects)} project(s)...")
|
|
# Note: _reindex_projects has its own cleanup, but run_with_cleanup
|
|
# ensures db.shutdown_db() is called even if _reindex_projects changes
|
|
run_with_cleanup(_reindex_projects(app_config))
|
|
console.print("[green]Reindex complete[/green]")
|