summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-06-12 16:49:01 +1000
committer2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-06-12 16:49:01 +1000
commita53a2568ec6e4e53d32a48443f50eee9d9fb8fcd (patch)
tree73a2ecf05724309738f783fc5ed20514768fc624
parentmaterial: better mono scheme (diff)
downloadcaelestia-cli-a53a2568ec6e4e53d32a48443f50eee9d9fb8fcd.tar.gz
caelestia-cli-a53a2568ec6e4e53d32a48443f50eee9d9fb8fcd.tar.bz2
caelestia-cli-a53a2568ec6e4e53d32a48443f50eee9d9fb8fcd.zip
scheme: fix not saving atomically
Causes programs which rely on the save file (e.g. the shell) to fail occasionally as they try to read while the cli is writing
-rw-r--r--src/caelestia/utils/paths.py10
-rw-r--r--src/caelestia/utils/scheme.py23
2 files changed, 21 insertions, 12 deletions
diff --git a/src/caelestia/utils/paths.py b/src/caelestia/utils/paths.py
index 6a6e0a8..3b5a7a6 100644
--- a/src/caelestia/utils/paths.py
+++ b/src/caelestia/utils/paths.py
@@ -1,5 +1,8 @@
import hashlib
+import json
import os
+import shutil
+import tempfile
from pathlib import Path
config_dir = Path(os.getenv("XDG_CONFIG_HOME", Path.home() / ".config"))
@@ -31,3 +34,10 @@ def compute_hash(path: str) -> str:
sha.update(chunk)
return sha.hexdigest()
+
+
+def atomic_dump(path: Path, content: dict[str, any]) -> None:
+ with tempfile.NamedTemporaryFile("w") as f:
+ json.dump(content, f)
+ f.flush()
+ shutil.move(f.name, path)
diff --git a/src/caelestia/utils/scheme.py b/src/caelestia/utils/scheme.py
index c978231..9027589 100644
--- a/src/caelestia/utils/scheme.py
+++ b/src/caelestia/utils/scheme.py
@@ -3,7 +3,7 @@ import random
from pathlib import Path
from caelestia.utils.material import get_colours_for_image
-from caelestia.utils.paths import scheme_data_dir, scheme_path
+from caelestia.utils.paths import atomic_dump, scheme_data_dir, scheme_path
class Scheme:
@@ -100,17 +100,16 @@ class Scheme:
def save(self) -> None:
scheme_path.parent.mkdir(parents=True, exist_ok=True)
- with scheme_path.open("w") as f:
- json.dump(
- {
- "name": self.name,
- "flavour": self.flavour,
- "mode": self.mode,
- "variant": self.variant,
- "colours": self.colours,
- },
- f,
- )
+ atomic_dump(
+ scheme_path,
+ {
+ "name": self.name,
+ "flavour": self.flavour,
+ "mode": self.mode,
+ "variant": self.variant,
+ "colours": self.colours,
+ },
+ )
def set_random(self) -> None:
self._name = random.choice(get_scheme_names())