feat(packaging): check Homebrew formula has a resource per runtime dependency

This commit is contained in:
beefcarver committed 2026-11-15 11:30:29 -05:00
1 parent 86b22226e2
commit 4c2f498e41
1 file changed
+47
+47
View File
@@ -335,6 +335,50 @@ def bump_srcinfo() -> None:
say("regenerated contrib/aur/.SRCINFO")
#: Names that may appear as `resource` blocks in the formula. A Python
#: dependency without one is silently skipped at install time because Homebrew
#: installs the sdist `--no-deps`, which surfaces as an ImportError on launch
#: rather than as a packaging error.
RESOURCE_LINE = re.compile(r'(?m)^ resource "([^"]+)" do$')
def pypi_name(name: str) -> str:
"""PEP 503 name: lowercase, runs of -_. collapsed to a single hyphen."""
return re.sub(r"[-_.]+", "-", name).lower()
def runtime_dependencies() -> list[str]:
"""The distribution names in `pyproject.toml`'s `[project] dependencies`."""
block = re.search(r"(?ms)^dependencies = \[(.*?)^\]$", PYPROJECT.read_text())
if block is None:
raise fail("no dependencies array in pyproject.toml")
return re.findall(r'^\s*"([A-Za-z0-9._-]+)', block.group(1), re.MULTILINE)
def formula_excluded_resources() -> set[str]:
"""Dependencies the formula deliberately leaves to other formulae."""
match = re.search(r'pypi_packages .*exclude_packages: "([^"]*)"', FORMULA.read_text())
if match is None:
return set()
return {pypi_name(name.strip()) for name in match.group(1).split(",") if name.strip()}
def check_formula_resources(problems: list[str]) -> None:
"""Every runtime dependency needs a `resource`, unless another formula has it."""
resources = {pypi_name(name) for name in RESOURCE_LINE.findall(FORMULA.read_text())}
if not resources:
problems.append("formula vendors no Python resources; it would install --no-deps")
excluded = formula_excluded_resources()
for dependency in runtime_dependencies():
name = pypi_name(dependency)
if name in excluded or name in resources:
continue
problems.append(
f"formula has no resource for {name}"
" (run `brew update-python-resources Formula/b/beefy-player.rb` in the tap)"
)
def bump_formula(version: str, checksum: str) -> None:
text = FORMULA.read_text()
url = RELEASE_ASSET.format(version=version, name=ASSET_NAME)
@@ -344,6 +388,8 @@ def bump_formula(version: str, checksum: str) -> None:
)
# The default branch is master, and --HEAD is only useful if it resolves.
text = text.replace('branch: "main"', 'branch: "master"')
# The `resource` blocks pin versions, not the release: they only go stale
# when pyproject.toml's dependencies change, which `--check` reports.
FORMULA.write_text(text)
say("wrote contrib/homebrew/Formula/b/beefy-player.rb")
@@ -435,6 +481,7 @@ def check(version: str) -> int:
problems.append('formula head branch is "main"; this repository uses master')
if re.search(r'sha256 "0{64}"', formula):
problems.append("formula still has the placeholder sha256")
check_formula_resources(problems)
for problem in problems:
say(f"drift: {problem}")