Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/codegraphcontext/cli/cli_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ async def _run_index_with_progress(graph_builder: GraphBuilder, path_obj: Path,
progress.update(task_id, total=job.total_files, completed=job.processed_files)

# Update the current filename in the UI
current_file = job.current_file or ""
current_file = job.current_file or job.status_message or ""
if len(current_file) > 40:
current_file = "..." + current_file[-37:]
progress.update(task_id, filename=current_file)
Expand Down
28 changes: 19 additions & 9 deletions src/codegraphcontext/core/database_kuzu.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,16 +298,26 @@ def _run_schema_migrations(self):
raise RuntimeError("Kuzu Schema Migration Failed") from e

def close_driver(self):
"""Closes the connection pool."""
"""Closes the connection pool and releases database resources."""
if self._db is not None:
info_logger("Closing KùzuDB connection pool")
# Clear the pool
while not self._pool.empty():
try:
self._pool.get_nowait()
except:
break
self._db = None
with self._lock:
if self._db is None:
return
info_logger("Closing KùzuDB connection pool")
# Clear and close all connections in the pool
while self._pool is not None and not self._pool.empty():
try:
conn = self._pool.get_nowait()
try:
conn.close()
except Exception:
pass
except:
break
self._pool = None
# Drop database reference to trigger KuzuDB cleanup
self._db = None
import gc; gc.collect()

def is_connected(self) -> bool:
"""Checks if the database connection is currently active."""
Expand Down
1 change: 1 addition & 0 deletions src/codegraphcontext/core/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class JobInfo:
total_files: int = 0
processed_files: int = 0
current_file: Optional[str] = None
status_message: Optional[str] = None
estimated_duration: Optional[float] = None
actual_duration: Optional[float] = None
errors: List[str] = None
Expand Down
12 changes: 8 additions & 4 deletions src/codegraphcontext/tools/code_finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,13 @@ def find_dead_code(self, exclude_decorated_with: Optional[List[str]] = None, rep

with self.driver.session() as session:
repo_filter = "AND func.path STARTS WITH $repo_path" if repo_path else ""
decorator_filter = "AND ALL(decorator_name IN $exclude_decorated_with WHERE NOT decorator_name IN func.decorators)" if exclude_decorated_with else ""
decorator_filter = ""
if exclude_decorated_with:
any_conditions = " AND ".join(
f"NOT ANY(d IN func.decorators WHERE d CONTAINS '{p.replace(chr(39), chr(39)+chr(39))}')"
for p in exclude_decorated_with
)
decorator_filter = f"AND {any_conditions}"
func_ignore = cypher_path_not_under_ignore_dirs("func.path")
caller_ignore = cypher_path_not_under_ignore_dirs("caller.path")

Expand Down Expand Up @@ -816,9 +822,7 @@ def find_dead_code(self, exclude_decorated_with: Optional[List[str]] = None, rep
params = {}
if repo_path:
params["repo_path"] = repo_path
if exclude_decorated_with:
params["exclude_decorated_with"] = exclude_decorated_with


result = session.run(query, **params)

return {
Expand Down
20 changes: 20 additions & 0 deletions src/codegraphcontext/tools/indexing/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ async def process_file(file: Path) -> Optional[Dict[str, Any]]:
)

t0 = time.time()
if job_id:
job_manager.update_job(job_id, status_message="Resolving inheritance links...")
info_logger(f"[INHERITS] Resolving inheritance links across {len(all_file_data)} files...")
inheritance_batch, csharp_files = build_inheritance_and_csharp_files(all_file_data, imports_map)
writer.write_inheritance_links(inheritance_batch, csharp_files, imports_map)
Expand All @@ -117,6 +119,8 @@ async def process_file(file: Path) -> Optional[Dict[str, Any]]:
None,
diagnostics=call_resolution_diagnostics,
)
if job_id:
job_manager.update_job(job_id, status_message="Writing function CALLS edges...")
writer.write_function_call_groups(*resolved_calls)
t2 = time.time()
info_logger(f"Function calls created in {t2 - t1:.1f}s. Total post-processing: {t2 - t0:.1f}s")
Expand All @@ -125,10 +129,14 @@ async def process_file(file: Path) -> Optional[Dict[str, Any]]:
# C++ method definitions live in .cpp while the Class node lives in .h.
# The per-file write cannot create these edges reliably due to ordering;
# this single repo-scoped pass runs after every node is in the graph.
if job_id:
job_manager.update_job(job_id, status_message="Linking C++ class-function edges...")
info_logger("[CPP] Linking C++ out-of-line method definitions to their classes...")
writer.write_cpp_class_function_links(resolved_repo_path_str)

# ── Spring injection edges (#887) ─────────────────────────────────────────
if job_id:
job_manager.update_job(job_id, status_message="Processing Spring injection edges...")
spring_inject_batch = []
for fd in all_file_data:
injections = fd.get("spring_injections")
Expand All @@ -155,6 +163,8 @@ async def process_file(file: Path) -> Optional[Dict[str, Any]]:

# ── Maven / Gradle build graph (#888) ────────────────────────────────────
if not is_dependency and path.is_dir():
if job_id:
job_manager.update_job(job_id, status_message="Processing Maven build graph...")
try:
from ...tools.languages.maven import parse_repo_maven
maven_data = parse_repo_maven(path.resolve())
Expand All @@ -163,6 +173,8 @@ async def process_file(file: Path) -> Optional[Dict[str, Any]]:
except Exception as _me:
info_logger(f"[MAVEN] Build graph failed (skipping): {_me}")

if job_id:
job_manager.update_job(job_id, status_message="Processing Gradle build graph...")
try:
from ...tools.languages.gradle import parse_repo_gradle
gradle_data = parse_repo_gradle(path.resolve())
Expand All @@ -172,6 +184,8 @@ async def process_file(file: Path) -> Optional[Dict[str, Any]]:
info_logger(f"[GRADLE] Build graph failed (skipping): {_ge}")

# ── ORM / datasource code linkage (#843) ─────────────────────────────────
if job_id:
job_manager.update_job(job_id, status_message="Processing ORM mappings...")
orm_batch = []
for fd in all_file_data:
orm_mappings = fd.get("orm_mappings")
Expand All @@ -189,6 +203,8 @@ async def process_file(file: Path) -> Optional[Dict[str, Any]]:

# ── MyBatis XML mapper READS / WRITES edges ───────────────────────────────
if not is_dependency and path.is_dir():
if job_id:
job_manager.update_job(job_id, status_message="Processing MyBatis XML mappers...")
try:
from ...tools.languages.mybatis import find_and_parse_mybatis_mappers
mybatis_batch = find_and_parse_mybatis_mappers(path.resolve())
Expand All @@ -200,6 +216,8 @@ async def process_file(file: Path) -> Optional[Dict[str, Any]]:
# ── Phase 4: embedding generation (optional, config-gated) ────────────────
from ...cli.config_manager import get_config_value as _gcv
if (_gcv("ENABLE_VECTOR_RESOLVE") or "false").lower() == "true":
if job_id:
job_manager.update_job(job_id, status_message="Generating embeddings...")
try:
from .embeddings import EmbeddingPipeline
repo_path_str = str(path.resolve())
Expand All @@ -211,6 +229,8 @@ async def process_file(file: Path) -> Optional[Dict[str, Any]]:

# ── Phase 5: inheritance-aware re-resolution (optional, config-gated) ─────
if (_gcv("ENABLE_INHERIT_RESOLVE") or "false").lower() == "true":
if job_id:
job_manager.update_job(job_id, status_message="Running inheritance re-resolution...")
try:
from .resolution.post_resolution import run_inheritance_reresolve
vector_resolver = None
Expand Down
Loading