def symbolic_link(src: Path, dest: Path): """Create an symbolic link from `src` to `dest` This context manager will create a symbolic link from src to dest. It differentiates itself from `Path.link_to()` by …: * … creating the link with root privileges. This allows to limit root permissions to only the necessary parts of the program. * ensuring that the link gets removed after usage. Parameters: ----------- src: Path to source; can be anything that has a filesystem path dest: Path to destination file Returns: -------- The value of `dest.absolute()` will be returned. """ if not src.exists(): raise FileNotFoundError if dest.exists(): raise FileExistsError absolute_dest = dest.absolute() sh.run_cmd( cmd=["sudo", "ln", "-s", f"{src.absolute()}", f"{absolute_dest}"]) try: yield absolute_dest finally: sh.run_cmd(cmd=["sudo", "rm", f"{absolute_dest}"])
def test_symbolic_link_does_not_crash_in_case_of_vanished_link() -> None: content = "some arbitrary content" with NamedTemporaryFile() as named_file: source = Path(named_file.name) source.write_text(content) in_dest = Path(get_random_filename()) with dm.symbolic_link(src=source, dest=in_dest) as out_dest: sh.run_cmd(cmd=["sudo", "rm", out_dest])
def mount_btrfs_device(device: Path, mount_dir: Path) -> None: cmd: sh.StrPathList = [ "sudo", "mount", "-o", "compress=zlib", device, mount_dir, ] sh.run_cmd(cmd=cmd)
def rsync_folder(src: Path, dest: Path) -> None: cmd: sh.StrPathList = [ "sudo", "rsync", "-ax", "--delete", "--inplace", f"{src}/", dest, ] sh.run_cmd(cmd=cmd)
def test_encrypt_device(big_file) -> None: pass_cmd = dm.generate_passcmd() result_uuid = dm.encrypt_device(big_file, pass_cmd) uuid_check_cmd = ["sudo", "cryptsetup", "luksUUID", big_file] uuid_check_proc = sh.run_cmd(cmd=uuid_check_cmd, capture_output=True) reported_uuid = UUID(uuid_check_proc.stdout.decode().strip()) assert result_uuid == reported_uuid
def get_mounted_devices() -> dict[str, set[Path]]: raw_mounts = sh.run_cmd(cmd=["mount"], capture_output=True) mount_lines = raw_mounts.stdout.decode().splitlines() mount_points = defaultdict(set) for line in mount_lines: device = line.split()[0] dest = Path(line.split()[2]) mount_points[device].add(dest) return dict(mount_points)
def rsync_file(src: Path, dest: Path) -> None: cmd: sh.StrPathList = ["sudo", "rsync", "-ax", "--inplace", src, dest] sh.run_cmd(cmd=cmd)
def snapshot(*, src: Path, dest: Path) -> None: cmd: sh.StrPathList = ["sudo", "btrfs", "subvolume", "snapshot", src, dest] sh.run_cmd(cmd=cmd)
def unmount_device(device: Path) -> None: cmd: sh.StrPathList = ["sudo", "umount", device] sh.run_cmd(cmd=cmd)
def close_decrypted_device(device: Path) -> None: if device.parent != Path("/dev/mapper"): raise InvalidDecryptedDevice map_name = device.name close_cmd = ["sudo", "cryptsetup", "close", map_name] sh.run_cmd(cmd=close_cmd)
def _mkfs_btrfs(file: Path) -> None: cmd: sh.StrPathList = ["sudo", "mkfs.btrfs", file] sh.run_cmd(cmd=cmd)
def mounted_directories(): with TemporaryDirectory() as src: with TemporaryDirectory() as mountpoint: sh.run_cmd(cmd=["sudo", "mount", "-o", "bind", src, mountpoint]) yield Path(src), Path(mountpoint) sh.run_cmd(cmd=["sudo", "umount", mountpoint])
def test_run_cmd_captures_output(message: str) -> None: proc = sh.run_cmd(cmd=["echo", message], capture_output=True) assert proc.returncode == 0 assert proc.stdout.strip().decode("utf-8") == message
def test_run_cmd_fails() -> None: with pytest.raises(CalledProcessError): sh.run_cmd(cmd=["false"])
def test_run_cmd_succeeds() -> None: proc = sh.run_cmd(cmd=["true"]) assert proc.returncode == 0