mirror of
https://github.com/hanzoai/font.git
synced 2026-11-02 23:42:52 +00:00
The estate carried Geist under our name in four repositories. Those files said family "Zen" and manufacturer "Hanzo AI, Inc." while their vendor tag was still VRCL and nameID 0 named one holder — a partial relabelling, which answers "Zen" to every question a stylesheet, a grep or a font menu asks. Family alone cannot tell you whose bytes these are; vendor and notice can. identity.py holds that answer once. name.py and notice.py write identity into a binary and each had its own copy of the notice text, free to drift; they now read it from one place. The same definition read backwards is the check, and copy-npm-fonts ends with it, so a face becomes something the package would publish and is refused in the same step. All 87 faces pass. Two things the check learned from being tested rather than assumed. A static cut outside the four styles a family can group puts its weight in nameID 1 and the shared family in nameID 16, so "Zen Thin" is correct and 16 is the field to read. And the notice lives in a Windows record and a Mac one: reading only the record fontTools hands you passes a face that rewrote just the other one, so every nameID 0 record must carry both holders.
61 lines
1.9 KiB
Python
61 lines
1.9 KiB
Python
"""Put the upstream copyright line back on the built families.
|
|
|
|
`name.py` names the hand-exported Zen Pixel cuts and writes nameID 0 as the
|
|
upstream notice above ours, because OFL §2 binds each copy of the Font Software
|
|
to the notice and a .woff2 served to a browser IS a copy travelling alone. The
|
|
fontmake-built families take the other path — their fields come from the Glyphs
|
|
sources via `scripts/set-fontinfo.py` — and that path wrote only our line, so
|
|
Zen and Zen Mono shipped without the notice the licence at the root already
|
|
carries. This puts them in agreement.
|
|
|
|
Sources are fixed too (set-fontinfo.py), so a rebuild produces this directly;
|
|
this exists for the binaries already built and committed.
|
|
|
|
python3 packages/zen/scripts/notice.py
|
|
|
|
Idempotent: a file already carrying both lines is left alone.
|
|
"""
|
|
import pathlib
|
|
import sys
|
|
|
|
from fontTools.ttLib import TTFont
|
|
|
|
from identity import NOTICE, OURS, UPSTREAM
|
|
|
|
ROOT = pathlib.Path(__file__).resolve().parents[3]
|
|
|
|
|
|
def fix(path: pathlib.Path) -> bool:
|
|
f = TTFont(str(path))
|
|
have = f['name'].getDebugName(0) or ''
|
|
if UPSTREAM in have and OURS in have:
|
|
return False
|
|
f['name'].setName(NOTICE, 0, 3, 1, 0x409)
|
|
f['name'].setName(NOTICE, 0, 1, 0, 0)
|
|
f.save(str(path))
|
|
return True
|
|
|
|
|
|
def main() -> int:
|
|
roots = [ROOT / 'fonts', ROOT / 'packages' / 'zen' / 'dist' / 'fonts']
|
|
seen = fixed = 0
|
|
for r in roots:
|
|
if not r.is_dir():
|
|
continue
|
|
for path in sorted(r.rglob('*')):
|
|
if path.suffix not in ('.otf', '.ttf', '.woff2'):
|
|
continue
|
|
seen += 1
|
|
if fix(path):
|
|
fixed += 1
|
|
if not seen:
|
|
print('no built faces found — run `make build` first', file=sys.stderr)
|
|
return 1
|
|
print(f'{fixed} of {seen} faces gained the upstream notice'
|
|
if fixed else f'all {seen} faces already carry both notices')
|
|
return 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|