Convert from Homebrew Formulae to Casks for font installation
Formulae can't install to ~/Library/Fonts/ due to Homebrew sandboxing. Casks have a built-in `font` artifact that handles this automatically. - Replace Formula/ with Casks/ directory - Rewrite generator to produce cask files instead of formulae - Add .ttc (TrueType Collection) support - Update all tests for cask format - Update CLI and documentation - Fonts with no installable files (TTF/OTF/TTC) are skipped Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
cb1918c30f
commit
76743cdc4d
273 changed files with 2509 additions and 10048 deletions
|
|
@ -1,105 +1,25 @@
|
|||
"""Verify that each font's formula install logic would copy the right files (simulated install)."""
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
"""Verify that each font's cask references valid font files that exist."""
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.conftest import (
|
||||
FONT_FILES_DIR,
|
||||
FORMULA_DIR,
|
||||
WEB_EXTENSIONS,
|
||||
get_font_dir_names,
|
||||
)
|
||||
|
||||
|
||||
def _run_install_simulation(font_name: str, font_dir: Path, prefix: Path, formula_name: str) -> None:
|
||||
"""
|
||||
Simulate the formula's install: copy ttf/otf/web/other_files to prefix
|
||||
as the formula would (same layout as homebrew-fonts/font_files/<font_name>/).
|
||||
"""
|
||||
# Layout formula expects: homebrew-fonts/font_files/<font_name>/{ttf,otf,web,other_files}
|
||||
# We use font_dir directly (same layout).
|
||||
(prefix / "fonts").mkdir(parents=True)
|
||||
(prefix / "fonts/truetype").mkdir(parents=True)
|
||||
(prefix / "fonts/opentype").mkdir(parents=True)
|
||||
(prefix / "fonts/webfonts").mkdir(parents=True)
|
||||
(prefix / formula_name).mkdir(parents=True)
|
||||
|
||||
for f in (font_dir / "ttf").glob("*.ttf"):
|
||||
shutil.copy2(f, prefix / "fonts/truetype" / f.name)
|
||||
for f in (font_dir / "otf").glob("*.otf"):
|
||||
shutil.copy2(f, prefix / "fonts/opentype" / f.name)
|
||||
web_dir = font_dir / "web"
|
||||
for f in web_dir.iterdir():
|
||||
if f.is_file() and f.suffix.lower() in WEB_EXTENSIONS:
|
||||
shutil.copy2(f, prefix / "fonts/webfonts" / f.name)
|
||||
other_src = font_dir / "other_files"
|
||||
if other_src.exists():
|
||||
for f in other_src.iterdir():
|
||||
dest = prefix / formula_name / f.name
|
||||
if f.is_dir():
|
||||
shutil.copytree(f, dest, dirs_exist_ok=True)
|
||||
else:
|
||||
shutil.copy2(f, dest)
|
||||
from tests.conftest import CASKS_DIR, FONT_FILES_DIR, get_font_dir_names
|
||||
|
||||
|
||||
@pytest.mark.parametrize("font_name", get_font_dir_names())
|
||||
def test_install_simulation_places_files(font_name):
|
||||
"""Simulate install for this font and assert expected files are present under prefix."""
|
||||
font_dir = FONT_FILES_DIR / font_name
|
||||
formula_name = font_name.replace("font-", "", 1)
|
||||
def test_cask_font_artifacts_are_installable(font_name):
|
||||
"""Each font artifact in the cask points to a real TTF or OTF file."""
|
||||
cask_path = CASKS_DIR / f"{font_name}.rb"
|
||||
if not cask_path.exists():
|
||||
pytest.skip(f"No cask for {font_name} (no TTF/OTF files)")
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
prefix = Path(tmp) / "prefix"
|
||||
prefix.mkdir()
|
||||
_run_install_simulation(font_name, font_dir, prefix, formula_name)
|
||||
content = cask_path.read_text()
|
||||
paths = re.findall(r'^\s*font\s+"([^"]+)"', content, re.MULTILINE)
|
||||
assert paths, f"{font_name}: cask has no font artifacts"
|
||||
|
||||
# Same assertions as the formula's test block: at least one expected path has content
|
||||
ttf_files = list((prefix / "fonts/truetype").glob("*.ttf"))
|
||||
otf_files = list((prefix / "fonts/opentype").glob("*.otf"))
|
||||
web_files = list((prefix / "fonts/webfonts").iterdir()) if (prefix / "fonts/webfonts").exists() else []
|
||||
other_dir = prefix / formula_name
|
||||
has_other = other_dir.exists() and any(other_dir.iterdir())
|
||||
|
||||
has_ttf = len(ttf_files) > 0
|
||||
has_otf = len(otf_files) > 0
|
||||
has_web = len(web_files) > 0
|
||||
|
||||
assert has_ttf or has_otf or has_web or has_other, (
|
||||
f"{font_name}: after simulated install, no files in share/fonts/truetype, "
|
||||
f"share/fonts/opentype, share/fonts/webfonts, or share/{formula_name}"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("font_name", get_font_dir_names())
|
||||
def test_install_simulation_file_counts_match_source(font_name):
|
||||
"""After simulated install, number of installed font files matches font_files/."""
|
||||
font_dir = FONT_FILES_DIR / font_name
|
||||
formula_name = font_name.replace("font-", "", 1)
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
prefix = Path(tmp) / "prefix"
|
||||
prefix.mkdir()
|
||||
_run_install_simulation(font_name, font_dir, prefix, formula_name)
|
||||
|
||||
ttf_src = len(list((font_dir / "ttf").glob("*.ttf")))
|
||||
otf_src = len(list((font_dir / "otf").glob("*.otf")))
|
||||
web_src = sum(
|
||||
1 for f in (font_dir / "web").iterdir()
|
||||
if f.is_file() and f.suffix.lower() in WEB_EXTENSIONS
|
||||
)
|
||||
|
||||
ttf_installed = len(list((prefix / "fonts/truetype").glob("*.ttf")))
|
||||
otf_installed = len(list((prefix / "fonts/opentype").glob("*.otf")))
|
||||
web_installed = len(list((prefix / "fonts/webfonts").iterdir()))
|
||||
|
||||
assert ttf_src == ttf_installed, (
|
||||
f"{font_name}: TTF count mismatch: source={ttf_src}, installed={ttf_installed}"
|
||||
)
|
||||
assert otf_src == otf_installed, (
|
||||
f"{font_name}: OTF count mismatch: source={otf_src}, installed={otf_installed}"
|
||||
)
|
||||
assert web_src == web_installed, (
|
||||
f"{font_name}: web font count mismatch: source={web_src}, installed={web_installed}"
|
||||
for rel_path in paths:
|
||||
full_path = FONT_FILES_DIR.parent / rel_path
|
||||
assert full_path.is_file(), f"{font_name}: missing font file: {rel_path}"
|
||||
assert full_path.suffix.lower() in (".ttf", ".otf", ".ttc"), (
|
||||
f"{font_name}: unexpected font type: {full_path.suffix}"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue