111 lines
3.6 KiB
Python
111 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
from typing import List, Tuple
|
|
import sys
|
|
import os
|
|
|
|
try:
|
|
from fontTools.ttLib import TTFont
|
|
except ImportError:
|
|
print("Need fonttools package, do `pip3 install fonttools`")
|
|
sys.exit(1)
|
|
|
|
# Fonts that are excluded from the license check
|
|
# Only add fonts that are known to be public domain or have a compatible license
|
|
_EXCLUDED_FONTS = {
|
|
"OpenTypeTest GPOS One",
|
|
}
|
|
|
|
# Font name mapping to remove any style suffix
|
|
_FONT_NAME_MAP = {
|
|
"Montserrat Medium": "Montserrat",
|
|
"Montserrat SemiBold": "Montserrat",
|
|
"Montserrat Bold": "Montserrat",
|
|
"Source Han Sans SC Normal": "Source Han Sans SC",
|
|
}
|
|
|
|
|
|
def get_font_full_name(font_path: str) -> str:
|
|
font = TTFont(font_path)
|
|
name_records = font["name"].names
|
|
fallback = None
|
|
for record in name_records:
|
|
if record.nameID == 1: # ID 1 corresponds to the font family name and will be used if full name doesn't exists
|
|
fallback = record.toStr()
|
|
if record.nameID == 4: # ID 4 corresponds to the full font name
|
|
return record.toStr()
|
|
return fallback
|
|
|
|
|
|
def list_intree_fonts(path: str) -> List[Tuple[str, str]]:
|
|
fonts = []
|
|
for root, _, files in os.walk(path):
|
|
for file in files:
|
|
if file.lower().endswith((".ttf", ".otf", ".woff", ".woff2")):
|
|
font_path = os.path.join(root, file)
|
|
font_name = get_font_full_name(font_path).strip()
|
|
if font_name:
|
|
# Add a no-strict mode to ignore missing license files
|
|
fonts.append((font_path, font_name))
|
|
return fonts
|
|
|
|
|
|
def has_intree_license(license_root_folder: str, font_name: str) -> bool:
|
|
if font_name in _EXCLUDED_FONTS:
|
|
return True
|
|
|
|
# Prepare candidate folder names, ignoring casing
|
|
candidates = {
|
|
font_name.lower(),
|
|
font_name.replace(" ", "_").lower(),
|
|
font_name.replace(" ", "").lower(),
|
|
}
|
|
|
|
if font_name in _FONT_NAME_MAP:
|
|
candidates.add(_FONT_NAME_MAP[font_name].lower())
|
|
candidates.add(_FONT_NAME_MAP[font_name].replace(" ", "_").lower())
|
|
candidates.add(_FONT_NAME_MAP[font_name].replace(" ", "").lower())
|
|
|
|
# List all directories in the license_root_folder
|
|
for entry in os.listdir(license_root_folder):
|
|
entry_path = os.path.join(license_root_folder, entry)
|
|
if os.path.isdir(entry_path):
|
|
# Compare the directory name in lowercase with candidates
|
|
if entry.lower() in candidates:
|
|
# Check if the directory contains at least one file (ignoring subdirectories)
|
|
for item in os.listdir(entry_path):
|
|
item_path = os.path.join(entry_path, item)
|
|
if os.path.isfile(item_path):
|
|
return True
|
|
return False
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser(description="Verify font licenses")
|
|
parser.add_argument(
|
|
"--no-strict",
|
|
action="store_true",
|
|
help="Ignore missing license files",
|
|
default=False,
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
SCRIPT_DIR = os.path.dirname(__file__)
|
|
# List of font files in the tree
|
|
fonts = list_intree_fonts(os.path.join(SCRIPT_DIR, ".."))
|
|
has_font_without_license = False
|
|
|
|
print("Verifying license for fonts:")
|
|
for path, name in fonts:
|
|
if has_intree_license(
|
|
os.path.join(SCRIPT_DIR, "built_in_font", "font_license"), name
|
|
):
|
|
print(f" [OK] '{name}'")
|
|
else:
|
|
print(f" [MISSING] '{name}' - {path}")
|
|
has_font_without_license = True
|
|
|
|
if has_font_without_license and not args.no_strict:
|
|
sys.exit(1)
|