refactor!: port shell scripts to Python package
Bash scripts were untestable and duplicated device/LUKS/mount logic; the lim/ package centralizes it behind one subprocess wrapper and a YAML image catalog (single point of truth). BREAKING CHANGE: scripts/*.sh removed. Use `lim --type <cmd>`; new types mount/umount/single-boot/raid1-boot/lock/unlock/import/export replace direct script calls. --extra is deprecated and ignored. - distributions.yml + lim/catalog.py hold the image catalog (PyYAML) - pytest suite: 102 tests with mocked subprocess (tests/unit) and a 250-line max file-length guard (tests/lint) - ruff strict (select ALL), GitHub Actions CI, Dependabot; Travis gone - Makefile: install (symlink ~/.local/bin/lim) and test targets - fixes over bash: SUDO_USER-aware chown, mmcblk/nvme partition paths, sha512 checksum support, whole-pipeline failure detection, blkid UUID fallback for pre-mounted images, conditional fstab seeding for PARTUUID/LABEL images, clean errors for missing binaries
This commit is contained in:
32
lim/fsutil.py
Normal file
32
lim/fsutil.py
Normal file
@@ -0,0 +1,32 @@
|
||||
"""Small file manipulation helpers."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from lim import ui
|
||||
from lim.errors import LimError
|
||||
|
||||
|
||||
def replace_in_file(search: str, replace: str, path: str | Path) -> None:
|
||||
"""Replace every literal occurrence of ``search``; fail when absent."""
|
||||
path = Path(path)
|
||||
text = path.read_text()
|
||||
new_text = text.replace(search, replace)
|
||||
if new_text == text:
|
||||
raise LimError(f"Search string '{search}' not found in {path}.")
|
||||
path.write_text(new_text)
|
||||
|
||||
|
||||
def ensure_line_in_file(line: str, path: str | Path) -> bool:
|
||||
"""Append ``line`` unless already present. Returns True when appended."""
|
||||
path = Path(path)
|
||||
content = path.read_text() if path.exists() else ""
|
||||
if line in content.splitlines():
|
||||
ui.warning(f"File {path} already contains the following entry:")
|
||||
print(line)
|
||||
ui.info("Skipped.")
|
||||
return False
|
||||
with path.open("a") as handle:
|
||||
if content and not content.endswith("\n"):
|
||||
handle.write("\n")
|
||||
handle.write(line + "\n")
|
||||
return True
|
||||
Reference in New Issue
Block a user