Synchronously indexes a repository in a given context.
(path: str, context: Optional[str] = None, no_progress: bool = False)
| 311 | |
| 312 | |
| 313 | def index_helper(path: str, context: Optional[str] = None, no_progress: bool = False): |
| 314 | """Synchronously indexes a repository in a given context.""" |
| 315 | time_start = time.time() |
| 316 | path_obj = Path(path).resolve() |
| 317 | # Normalize to forward slashes for cross-platform DB consistency. |
| 318 | # The graph DB always stores paths via Path.resolve().as_posix(), |
| 319 | # so Cypher queries must also use forward slashes on Windows. |
| 320 | repo_path_str = path_obj.as_posix() |
| 321 | index_cwd = path_obj if path_obj.is_dir() else path_obj.parent |
| 322 | services = _initialize_services(context, cwd=index_cwd) |
| 323 | if not all(services[:3]): |
| 324 | _fail_services_init() |
| 325 | |
| 326 | db_manager, graph_builder, code_finder, ctx = services |
| 327 | |
| 328 | if not path_obj.exists(): |
| 329 | console.print(f"[red]Error: Path does not exist: {path_obj}[/red]") |
| 330 | db_manager.close_driver() |
| 331 | raise typer.Exit(code=1) |
| 332 | |
| 333 | indexed_repos = code_finder.list_indexed_repositories() |
| 334 | repo_exists = any_repo_matches_path(indexed_repos, path_obj) |
| 335 | |
| 336 | if repo_exists: |
| 337 | # Check if the repository actually has files (not just an empty node from interrupted indexing) |
| 338 | # Use variable-length path to handle both flat (Repository->File) and |
| 339 | # hierarchical (Repository->Directory->...->File) graph structures |
| 340 | try: |
| 341 | with db_manager.get_driver().session() as session: |
| 342 | result = session.run( |
| 343 | "MATCH (r:Repository {path: $path})-[:CONTAINS*]->(f:File) RETURN count(DISTINCT f) as file_count", |
| 344 | path=repo_path_str |
| 345 | ) |
| 346 | record = result.single() |
| 347 | file_count = record["file_count"] if record else 0 |
| 348 | |
| 349 | if file_count > 0: |
| 350 | expected = graph_builder.estimate_processing_time(path_obj) if path_obj.is_dir() else None |
| 351 | expected_file_count = expected[0] if expected else None |
| 352 | if expected_file_count is None or file_count >= expected_file_count: |
| 353 | console.print(f"[yellow]Repository '{path}' is already indexed with {file_count} files. Skipping.[/yellow]") |
| 354 | console.print("[dim]💡 Tip: Use 'cgc index --force' to re-index[/dim]") |
| 355 | db_manager.close_driver() |
| 356 | return |
| 357 | console.print( |
| 358 | f"[yellow]Repository '{path}' has only {file_count} of {expected_file_count} files indexed. Continuing.[/yellow]" |
| 359 | ) |
| 360 | else: |
| 361 | console.print(f"[yellow]Repository '{path}' exists but has no files (likely interrupted). Re-indexing...[/yellow]") |
| 362 | except Exception as e: |
| 363 | console.print(f"[yellow]Warning: Could not check file count: {e}. Proceeding with indexing...[/yellow]") |
| 364 | |
| 365 | if context and ctx.mode == "named": |
| 366 | if not register_repo_in_context(context, str(path_obj), auto_create=False): |
| 367 | db_manager.close_driver() |
| 368 | raise typer.Exit(code=1) |
| 369 | |
| 370 | console.print(f"Starting indexing for: {path_obj}") |
no test coverage detected