scripts/check-uv-lock-export-drift.py
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env python3
"""Fail unless requirements.lock is the exact frozen export of uv.lock."""
from __future__ import annotations
import shutil
import subprocess
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
UV_LOCK = REPO / "uv.lock"
REQUIREMENTS_LOCK = REPO / "requirements.lock"
_EXPORT_ARGS = (
"export",
"--frozen",
"--no-emit-workspace",
"--no-dev",
"--format",
"requirements-txt",
"--no-emit-package",
"kotakneoapi",
"--no-emit-package",
"upstox-python-sdk",
)
class ExportError(RuntimeError):
"""Raised when a fresh frozen uv export cannot be produced."""
def _export_requirements() -> str:
uv = shutil.which("uv")
if uv is None:
raise ExportError("uv is unavailable; cannot verify requirements.lock")
try:
completed = subprocess.run( # noqa: S603 - resolved trusted tool with fixed arguments
[uv, *_EXPORT_ARGS],
cwd=REPO,
check=False,
capture_output=True,
text=True,
timeout=120,
)
except (OSError, subprocess.TimeoutExpired) as exc:
raise ExportError(f"uv export failed: {type(exc).__name__}") from exc
if completed.returncode != 0:
detail = completed.stderr.strip().splitlines()
suffix = f": {detail[-1]}" if detail else ""
raise ExportError(f"uv export failed with exit {completed.returncode}{suffix}")
if not completed.stdout:
raise ExportError("uv export returned no requirements")
return completed.stdout
def _without_generated_header(value: str) -> str:
lines = value.splitlines(keepends=True)
if (
len(lines) >= 2
and lines[0].startswith("# This file was autogenerated by uv")
and lines[1].startswith("# uv export")
):
return "".join(lines[2:])
return value
def main() -> int:
missing = [str(path) for path in (UV_LOCK, REQUIREMENTS_LOCK) if not path.is_file()]
if missing:
print("missing lockfile(s): " + ", ".join(missing))
return 1
try:
actual = REQUIREMENTS_LOCK.read_text(encoding="utf-8")
exported = _export_requirements()
except (OSError, UnicodeError, ExportError) as exc:
print(str(exc))
return 1
if _without_generated_header(actual) != _without_generated_header(exported):
command = "uv " + " ".join(_EXPORT_ARGS) + " --output-file requirements.lock"
print("requirements.lock does not match the frozen uv export")
print(f"regenerate with: {command}")
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())