flake history: make operations atomic
This commit is contained in:
@@ -5,19 +5,22 @@ from pathlib import Path
|
||||
from clan_cli.dirs import user_history_file
|
||||
|
||||
from ..async_cmd import CmdOut, runforcli
|
||||
from ..locked_open import locked_open
|
||||
|
||||
|
||||
async def add_flake(path: Path) -> dict[str, CmdOut]:
|
||||
user_history_file().parent.mkdir(parents=True, exist_ok=True)
|
||||
# append line to history file
|
||||
# TODO: Make this atomic
|
||||
lines: set[str] = set()
|
||||
if user_history_file().exists():
|
||||
with open(user_history_file()) as f:
|
||||
lines = set(f.readlines())
|
||||
lines.add(str(path))
|
||||
with open(user_history_file(), "w") as f:
|
||||
lines: set = set()
|
||||
old_lines = set()
|
||||
with locked_open(user_history_file(), "w+") as f:
|
||||
old_lines = set(f.readlines())
|
||||
lines = old_lines | {str(path)}
|
||||
if old_lines != lines:
|
||||
f.seek(0)
|
||||
f.writelines(lines)
|
||||
f.truncate()
|
||||
return {}
|
||||
|
||||
|
||||
|
||||
@@ -4,12 +4,14 @@ from pathlib import Path
|
||||
|
||||
from clan_cli.dirs import user_history_file
|
||||
|
||||
from ..locked_open import locked_open
|
||||
|
||||
|
||||
def list_history() -> list[Path]:
|
||||
if not user_history_file().exists():
|
||||
return []
|
||||
# read path lines from history file
|
||||
with open(user_history_file()) as f:
|
||||
with locked_open(user_history_file()) as f:
|
||||
lines = f.readlines()
|
||||
return [Path(line.strip()) for line in lines]
|
||||
|
||||
|
||||
15
pkgs/clan-cli/clan_cli/locked_open.py
Normal file
15
pkgs/clan-cli/clan_cli/locked_open.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import fcntl
|
||||
from collections.abc import Generator
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@contextmanager
|
||||
def locked_open(filename: str | Path, mode: str = "r") -> Generator:
|
||||
"""
|
||||
This is a context manager that provides an advisory write lock on the file specified by `filename` when entering the context, and releases the lock when leaving the context. The lock is acquired using the `fcntl` module's `LOCK_EX` flag, which applies an exclusive write lock to the file.
|
||||
"""
|
||||
with open(filename, mode) as fd:
|
||||
fcntl.flock(fd, fcntl.LOCK_EX)
|
||||
yield fd
|
||||
fcntl.flock(fd, fcntl.LOCK_UN)
|
||||
Reference in New Issue
Block a user