Ruby's cp raises EPERM if the target file already exists. Using system "cp", "-f" overwrites gracefully. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
176 lines
No EOL
6 KiB
Python
Executable file
176 lines
No EOL
6 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
import re
|
|
from pathlib import Path
|
|
|
|
|
|
def formula_name_to_class(formula_name: str) -> str:
|
|
"""Convert formula name (e.g. 'acrylic-hand', 'graham_hand') to valid Ruby PascalCase."""
|
|
# Split on hyphens and underscores, capitalize each segment, join (no separators)
|
|
parts = re.split(r"[-_]+", formula_name)
|
|
return "".join(p.capitalize() for p in parts if p)
|
|
|
|
|
|
class HomebrewFormulaGenerator:
|
|
def __init__(self, fonts_dir):
|
|
self.fonts_dir = Path(fonts_dir)
|
|
self.formula_dir = self.fonts_dir.parent / "Formula"
|
|
self.formula_dir.mkdir(exist_ok=True)
|
|
self.web_extensions = (".woff", ".woff2", ".eot", ".svg")
|
|
|
|
def _font_has_files(self, font_dir: Path) -> tuple[bool, bool, bool, bool]:
|
|
"""Return (has_ttf, has_otf, has_web, has_other) for the font folder."""
|
|
has_ttf = any((font_dir / "ttf").glob("*.ttf"))
|
|
has_otf = any((font_dir / "otf").glob("*.otf"))
|
|
web_dir = font_dir / "web"
|
|
has_web = any(
|
|
f.suffix.lower() in self.web_extensions for f in web_dir.glob("*") if f.is_file()
|
|
)
|
|
other_dir = font_dir / "other_files"
|
|
has_other = any(other_dir.iterdir()) if other_dir.exists() else False
|
|
return (has_ttf, has_otf, has_web, has_other)
|
|
|
|
def _generate_test_block(
|
|
self, formula_name: str, has_ttf: bool, has_otf: bool, has_web: bool, has_other: bool
|
|
) -> str:
|
|
"""Generate test block that asserts at least one install path has files for this formula."""
|
|
assertions = []
|
|
if has_ttf:
|
|
assertions.append('assert (share/"fonts/truetype").glob("*.ttf").any?, "No TTF fonts installed"')
|
|
if has_otf:
|
|
assertions.append('assert (share/"fonts/opentype").glob("*.otf").any?, "No OTF fonts installed"')
|
|
if has_web:
|
|
assertions.append(
|
|
'assert (share/"fonts/webfonts").glob("*").any?, "No web fonts installed"'
|
|
)
|
|
if has_other:
|
|
assertions.append(
|
|
f'assert_predicate share/"{formula_name}", :directory?, "Other files dir missing"'
|
|
)
|
|
if not assertions:
|
|
assertions.append(
|
|
f'assert_predicate share/"{formula_name}", :directory?, "Formula share dir missing"'
|
|
)
|
|
return "\n ".join(assertions)
|
|
|
|
def generate_formula_content(
|
|
self,
|
|
font_name: str,
|
|
formula_name: str,
|
|
has_ttf: bool,
|
|
has_otf: bool,
|
|
has_web: bool,
|
|
has_other: bool,
|
|
) -> str:
|
|
"""Generate the Ruby formula content for a font."""
|
|
class_name = formula_name_to_class(formula_name)
|
|
extensions = []
|
|
if has_ttf:
|
|
extensions.append("TTF")
|
|
if has_otf:
|
|
extensions.append("OTF")
|
|
if has_web:
|
|
extensions.append("web")
|
|
ext_comment = " ".join(extensions) if extensions else "other_files only"
|
|
test_block = self._generate_test_block(
|
|
formula_name, has_ttf, has_otf, has_web, has_other
|
|
)
|
|
return f"""# typed: false
|
|
# frozen_string_literal: true
|
|
|
|
# This file was generated by the font folder cleanup script
|
|
# Do not edit this file directly
|
|
# Installs: {ext_comment}
|
|
|
|
class Font{class_name} < Formula
|
|
desc "Font: {formula_name}"
|
|
homepage "http://clancy.genet-godzilla.ts.net:8085/Fonts/homebrew-fonts"
|
|
url "http://clancy.genet-godzilla.ts.net:8085/Fonts/homebrew-fonts/archive/main.tar.gz"
|
|
version "1.0.0"
|
|
|
|
def install
|
|
# Create font directories
|
|
(share/"fonts").mkpath
|
|
(share/"fonts/truetype").mkpath
|
|
(share/"fonts/opentype").mkpath
|
|
(share/"fonts/webfonts").mkpath
|
|
|
|
# Install TTF fonts
|
|
Dir.glob("font_files/{font_name}/ttf/*.ttf").each do |font|
|
|
system "cp", font, share/"fonts/truetype"
|
|
end
|
|
|
|
# Install OTF fonts
|
|
Dir.glob("font_files/{font_name}/otf/*.otf").each do |font|
|
|
system "cp", font, share/"fonts/opentype"
|
|
end
|
|
|
|
# Install web fonts
|
|
Dir.glob("font_files/{font_name}/web/*.{{woff,woff2,eot,svg}}").each do |font|
|
|
system "cp", font, share/"fonts/webfonts"
|
|
end
|
|
|
|
# Install documentation and other files
|
|
(share/"{formula_name}").mkpath
|
|
Dir.glob("font_files/{font_name}/other_files/*").each do |file|
|
|
system "cp", "-r", file, share/"{formula_name}"
|
|
end
|
|
end
|
|
|
|
def post_install
|
|
user_fonts = Pathname.new(File.expand_path("~/Library/Fonts"))
|
|
user_fonts.mkpath
|
|
|
|
Dir.glob(share/"fonts/truetype/*.ttf").each do |f|
|
|
system "cp", "-f", f, user_fonts.to_s
|
|
end
|
|
Dir.glob(share/"fonts/opentype/*.otf").each do |f|
|
|
system "cp", "-f", f, user_fonts.to_s
|
|
end
|
|
end
|
|
|
|
def caveats
|
|
<<~EOS
|
|
Fonts have been copied to ~/Library/Fonts/ and should appear in Font Book.
|
|
|
|
Web fonts and other files are available in:
|
|
#{{share}}/fonts/webfonts
|
|
#{{share}}/{formula_name}
|
|
EOS
|
|
end
|
|
|
|
test do
|
|
{test_block}
|
|
end
|
|
end
|
|
"""
|
|
|
|
def generate_formulas(self):
|
|
"""Generate Homebrew formulas for all font folders."""
|
|
for font_dir in sorted(self.fonts_dir.glob("font-*")):
|
|
if not font_dir.is_dir():
|
|
continue
|
|
|
|
font_name = font_dir.name
|
|
formula_name = font_name.replace("font-", "", 1)
|
|
has_ttf, has_otf, has_web, has_other = self._font_has_files(font_dir)
|
|
formula_content = self.generate_formula_content(
|
|
font_name, formula_name, has_ttf, has_otf, has_web, has_other
|
|
)
|
|
formula_path = self.formula_dir / f"font-{formula_name}.rb"
|
|
formula_path.write_text(formula_content)
|
|
print(f"Generated formula for font-{formula_name}")
|
|
|
|
def main():
|
|
# Get the absolute path to the font_files directory
|
|
script_dir = Path(__file__).parent
|
|
fonts_dir = script_dir.parent / 'font_files'
|
|
|
|
if not fonts_dir.exists():
|
|
print(f"Error: Font directory not found: {fonts_dir}")
|
|
return
|
|
|
|
generator = HomebrewFormulaGenerator(fonts_dir)
|
|
generator.generate_formulas()
|
|
|
|
if __name__ == "__main__":
|
|
main() |