ReMe/reme4/steps/background/index_changes.py
Sen Huang 7d0bec60be
Some checks failed
Pre-commit / run (ubuntu-latest) (push) Has been cancelled
Tests ReMe / Unit Tests - py3.10 (push) Has been cancelled
Tests ReMe / Unit Tests - py3.13 (push) Has been cancelled
feat: rename working_dir to vault_dir and update documentation (#254)
* feat: rename working_dir to vault_dir and update documentation

- Rename working_dir to vault_dir across the application
- Update documentation to reflect vault_dir instead of working_dir
- Change FileFrontMatter title field to name field
- Update .gitignore to include vault directory
- Modify file path descriptions to reference vault instead of working_dir
- Update related configuration and property names accordingly

* refactor(steps): rename working_path to vault_path in CRUD operations

- Rename parameter from `working_path` to `vault_path` in `resolve_path` function
- Update all usages in append, edit, read, and write steps to use `self.vault_path`
- Update documentation comments to reflect the new parameter name
- Update docstring in read.py to mention `vault_dir` instead of `vault`

test(chunked_file_parser): update frontmatter field from title to name

- Change frontmatter field from `title` to `name` in test cases
- Update comment in background steps test to reference `vault_path` instead of `working_path`

* refactor(schema): remove unused ResourceEntry import

* feat(file_graph): add link scope filtering to get_inlinks/get_outlinks

* feat(file-store): add scope parameter to link methods
2026-05-22 18:10:29 +08:00

81 lines
3.6 KiB
Python

"""Index a batch of file changes into file_store."""
from pathlib import Path
from watchfiles import Change
from ..base_step import BaseStep
from ...components import R
from ...schema import FileChunk, FileNode
@R.register("index_changes_step")
class IndexChangesStep(BaseStep):
"""Classify raw watcher changes and index them into file_store."""
async def execute(self):
assert self.context is not None
# Each item: {"change": Change | "added"|"modified"|"deleted", "path": absolute path}
changes: list[dict] = self.context.get("changes") or []
buckets: dict[Change, list[str]] = {Change.added: [], Change.modified: [], Change.deleted: []}
for item in changes:
c = item["change"]
if isinstance(c, str):
c = Change.__members__.get(c)
if isinstance(c, Change) and c in buckets:
buckets[c].append(item["path"])
results: list[dict] = []
for change, action in ((Change.added, "Adding"), (Change.modified, "Updating")):
paths = buckets[change]
if not paths:
continue
self.logger.info(f"Detected {len(paths)} {change.name} file(s)")
parsed: list[tuple[FileNode, list[FileChunk]]] = []
ok_paths: list[str] = []
for path in paths:
abs_path = Path(path)
if not abs_path.is_file():
results.append({"change": change.name, "path": path, "success": False, "error": "not a file"})
continue
self.logger.info(f"{action} file: {path}")
try:
parsed.append(await self.parse_file(abs_path))
ok_paths.append(path)
except Exception as e:
self.logger.exception(f"Failed to parse {path}")
results.append({"change": change.name, "path": path, "success": False, "error": str(e)})
if parsed:
try:
await self.file_store.delete([n.path for n, _ in parsed])
await self.file_store.upsert(parsed)
results.extend({"change": change.name, "path": p, "success": True} for p in ok_paths)
except Exception as e:
self.logger.exception(f"Failed to persist {len(parsed)} {change.name} file(s)")
results.extend(
{"change": change.name, "path": p, "success": False, "error": str(e)} for p in ok_paths
)
if deleted := buckets[Change.deleted]:
if self.file_store is None:
raise RuntimeError("file_store is not initialized!")
self.logger.info(f"Detected {len(deleted)} deleted file(s)")
rel_deleted: list[str] = []
for path in deleted:
p = Path(path).absolute()
try:
rel_deleted.append(str(p.relative_to(self.vault_path)))
except ValueError:
rel_deleted.append(str(p))
try:
await self.file_store.delete(rel_deleted)
results.extend({"change": "deleted", "path": p, "success": True} for p in deleted)
except Exception as e:
self.logger.exception(f"Failed to delete {len(deleted)} file(s)")
results.extend({"change": "deleted", "path": p, "success": False, "error": str(e)} for p in deleted)
self.context.response.answer = results
self.context.response.success = all(r["success"] for r in results) if results else True
return self.context.response