lloom-client 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lloom/__init__.py +3 -0
- lloom/_fs.py +52 -0
- lloom/cli.py +894 -0
- lloom/client.py +307 -0
- lloom/config.py +87 -0
- lloom/embed.py +48 -0
- lloom/mailstore.py +561 -0
- lloom/proxy.py +257 -0
- lloom/py.typed +0 -0
- lloom/skills_install.py +411 -0
- lloom_client-0.1.0.dist-info/METADATA +167 -0
- lloom_client-0.1.0.dist-info/RECORD +15 -0
- lloom_client-0.1.0.dist-info/WHEEL +4 -0
- lloom_client-0.1.0.dist-info/entry_points.txt +2 -0
- lloom_client-0.1.0.dist-info/licenses/LICENSE +21 -0
lloom/__init__.py
ADDED
lloom/_fs.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Shared crash-safe filesystem helpers (client)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import uuid
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def fsync_dir(path: Path | str) -> None:
|
|
11
|
+
"""fsync a directory so a just-created/renamed entry survives a host
|
|
12
|
+
crash (fsyncing file contents alone does not persist the name)."""
|
|
13
|
+
fd = os.open(Path(path), os.O_RDONLY)
|
|
14
|
+
try:
|
|
15
|
+
os.fsync(fd)
|
|
16
|
+
except OSError:
|
|
17
|
+
pass # some filesystems refuse directory fsync; best effort
|
|
18
|
+
finally:
|
|
19
|
+
os.close(fd)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def atomic_write_text(path: Path | str, text: str, mode: int = 0o600) -> None:
|
|
23
|
+
"""Crash-safe text write: unique temp file in the same folder,
|
|
24
|
+
flush+fsync, then atomic ``os.replace`` (same filesystem) so readers
|
|
25
|
+
never see a partial file under the final name, and an fsync of the
|
|
26
|
+
parent directory so the new name itself survives a host crash. The
|
|
27
|
+
unique temp name keeps concurrent writers to the same target from
|
|
28
|
+
clobbering each other's temp files; the temp is removed if any step
|
|
29
|
+
fails — a failed write leaves no ``.tmp`` leftovers and the previous
|
|
30
|
+
content (if any) untouched.
|
|
31
|
+
"""
|
|
32
|
+
path = Path(path)
|
|
33
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
34
|
+
tmp = path.with_name(f".{path.name}.{os.getpid()}.{uuid.uuid4().hex}.tmp")
|
|
35
|
+
try:
|
|
36
|
+
# newline="": no translation — "\n" stays "\n" (and "\r" untouched)
|
|
37
|
+
# on every platform, preserving byte-exact mail file contents
|
|
38
|
+
fd = os.open(tmp, os.O_WRONLY | os.O_CREAT | os.O_EXCL, mode)
|
|
39
|
+
# respect a restrictive umask only for widening: never more permissive
|
|
40
|
+
os.fchmod(fd, mode)
|
|
41
|
+
with os.fdopen(fd, "w", encoding="utf-8", newline="") as fh:
|
|
42
|
+
fh.write(text)
|
|
43
|
+
fh.flush()
|
|
44
|
+
os.fsync(fh.fileno())
|
|
45
|
+
os.replace(tmp, path)
|
|
46
|
+
fsync_dir(path.parent)
|
|
47
|
+
except BaseException:
|
|
48
|
+
try:
|
|
49
|
+
os.unlink(tmp)
|
|
50
|
+
except OSError:
|
|
51
|
+
pass
|
|
52
|
+
raise
|