"""Cooperative local data lock. The runner holds a shared lock until it exits."""
from contextlib import contextmanager
from pathlib import Path
import fcntl
import os
import stat


class DataBusy(RuntimeError):
    pass


@contextmanager
def data_lock(root, *, exclusive=False, create=False):
    root=Path(root)
    if create:root.mkdir(parents=True,exist_ok=True,mode=0o700)
    descriptor=os.open(root/'.data.lock',os.O_RDWR|os.O_CREAT|os.O_NOFOLLOW,0o600)
    try:
        info=os.fstat(descriptor)
        if not stat.S_ISREG(info.st_mode) or info.st_nlink!=1:
            raise DataBusy('The local data lock is not a private regular file.')
        try:fcntl.flock(descriptor,(fcntl.LOCK_EX if exclusive else fcntl.LOCK_SH)|fcntl.LOCK_NB)
        except BlockingIOError:
            raise DataBusy('Stop every local app using this data folder before backup. A recovery operation may also be running.') from None
        yield
    finally:
        os.close(descriptor)
