Merge pull request #18 from alexwlchan/atomic-writes
- ID
fab85c5- date
2024-08-24 09:31:26+00:00- author
Alex Chan <alex@alexwlchan.net>- parents
dac85ff,87a066d- message
Merge pull request #18 from alexwlchan/atomic-writes Writing a file in `write_text()` is now atomic- changed files
1 file, 18 additions, 1 deletion
Changed files
src/javascript/__init__.py (5019) → src/javascript/__init__.py (5749)
diff --git a/src/javascript/__init__.py b/src/javascript/__init__.py
index 36ec47f..f40cb41 100644
--- a/src/javascript/__init__.py
+++ b/src/javascript/__init__.py
@@ -15,6 +15,7 @@ import json
import pathlib
import re
import typing
+import uuid
__version__ = "0.0.1"
@@ -71,7 +72,23 @@ def write_js(p: pathlib.Path | str, *, value: typing.Any, varname: str) -> None:
js_string = f"const {varname} = {json_string};\n"
p.parent.mkdir(exist_ok=True, parents=True)
- p.write_text(js_string)
+
+ # Write to a temporary file first, then rename this into place.
+ #
+ # This gives us pseudo-atomic writes -- it's probably not perfect, but
+ # it avoids situations where:
+ #
+ # * Somebody tries to read the file, and it contains a partial JS string
+ # * The write is interrupted, and the file is left empty
+ #
+ # Both of which have happened! Because I often use this running on
+ # files on a semi-slow external hard drive, and sometimes things break.
+ #
+ # The UUID is probably overkill because it would be very unusual for
+ # me to have multiple, concurrent writes going on, but it doesn't hurt.
+ tmp_p = p.with_suffix(f".{uuid.uuid4()}.js.tmp")
+ tmp_p.write_text(js_string)
+ tmp_p.rename(p)
def append_to_js_array(p: pathlib.Path | str, *, value: typing.Any) -> None: