import time
import os
import contextlib
from pathlib import Path

class LockAcquisitionError(Exception):
    pass

@contextlib.contextmanager
def FileLock(lock_dir: Path, name: str, timeout: int = 10, backoff: float = 0.5):
    """
    A file-based lock using atomic file creation mode ('x').
    Retries with an exponential-like or constant backoff until timeout.
    """
    lock_dir = Path(lock_dir)
    lock_dir.mkdir(parents=True, exist_ok=True)
    lock_file = lock_dir / f"{name}.lock"
    
    start_time = time.time()
    acquired = False
    
    while time.time() - start_time < timeout:
        try:
            # Atomic creation. Fails if file already exists.
            with open(lock_file, "x") as f:
                f.write(str(os.getpid()))
            acquired = True
            break
        except FileExistsError:
            time.sleep(backoff)
            
    if not acquired:
        raise LockAcquisitionError(f"Could not acquire lock '{name}' within {timeout} seconds")
        
    try:
        yield
    finally:
        try:
            if lock_file.exists():
                lock_file.unlink()
        except OSError:
            pass
