mirror of
https://github.com/safishamsi/graphify.git
synced 2026-10-20 19:01:24 +00:00
fix(io): write graph.json and manifest.json atomically
graph.json (the clustered `to_json` write and the `--no-cluster`/merge raw dumps) and manifest.json were written with a direct `open()`/`write_text`, so a crash, kill, or disk-full mid-write left a truncated, unparseable file that the next load or `detect_incremental` then failed on. Add `write_text_atomic`/`write_json_atomic` in graphify.paths (temp file in the same directory + `os.replace`; JSON is streamed into the temp, not materialized as one string) and route the graph.json writers (export.to_json, cli._prune_graph_json_sources, the merge driver) plus detect.save_manifest through them. The helper preserves the destination's mode (an atomic replace never tightens 0644 to mkstemp's 0600), writes through a symlinked destination (shared-output setups), and falls back to copy-then-delete on a Windows os.replace lock — matching graphify.cache's existing atomic writer. On failure the previous file is left intact and the temp removed. Not a power-loss durability guarantee (no fsync, consistent with the rest of the codebase).
This commit is contained in:
1 parent
7d53a02704
commit
f38e98012d
5 files changed
+181
-6
No files matched your search
+3
-2
@@ -315,8 +315,9 @@ def to_json(G: nx.Graph, communities: dict[int, list[str]], output_path: str, *,
|
||||
commit = built_at_commit if built_at_commit is not None else _git_head()
|
||||
if commit:
|
||||
data["built_at_commit"] = commit
|
||||
with open(output_path, "w", encoding="utf-8") as f: # nosec
|
||||
json.dump(data, f, indent=2)
|
||||
from graphify.paths import write_json_atomic
|
||||
# Atomic write: a crash/ENOSPC mid-write must not truncate a good graph.json.
|
||||
write_json_atomic(output_path, data, indent=2)
|
||||
return True
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user