ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

FiraCode 上架 Google Fonts 的 QA 流水线:构建、FontBakery 检查与元数据修复实操

FiraCode 上架 Google Fonts 的 QA 流水线:构建、FontBakery 检查与元数据修复实操 FiraCode 上架 Google Fonts 的 QA 流水线构建、FontBakery 检查与元数据修复实操【免费下载链接】FiraCodeFree monospaced font with programming ligatures项目地址: https://gitcode.com/GitHub_Trending/fi/FiraCodeFira Code 想进入 Google Fonts就必须通过 Google Fonts 的准入门槛产出符合规范的变量字体与静态字体、满足垂直度量等元数据标准并逐条消除 FontBakery 工具报告的失败项。本文基于 googlefonts-qa/README.md 这条主线完整还原“环境准备 → 构建 → 搬运并检查 → 读报告 → 修复 → 重建”的迭代闭环并结合 move-check.sh、QA-notes.md 与 set-vertical-metrics.py 等仓库内真实文件讲清每个检查失败项背后的具体修复手段。一、这套 QA 工具链要解决什么问题googlefonts-qa/目录是 Fira Code 项目专门用于 Google Fonts 准入onboarding的工作区。按 README 的描述它由两个脚本驱动build.sh按 Google Fonts 的要求构建变量字体与静态字体文件move-check.sh做三件事——修正若干字体元数据以对齐 Google Fonts 标准、把字体文件搬进本地google/fonts仓库的目录结构为给官方 google/fonts 仓库提 PR 做准备、运行 FontBakery 对字体做标准检查并把结果以 Markdown 形式保存到checks/子目录。README 特别强调这个过程必须反复执行——“修改源文件、重建输出字体、解决 FontBakery 标记的问题”是一个循环而不是一次性操作。目录中各文件的分工如下路径作用METADATA.pbGoogle Fonts 家族元数据字重、风格等随字体一起拷入目标目录gfonts-description.htmlGoogle Fonts 页面展示用的字体描述页会被重命名为DESCRIPTION.en_us.htmlscripts/move-check.sh搬运字体、修正元数据、运行 FontBakery 的主脚本scripts/requirements.txtQA 阶段 Python 依赖清单scripts/set-vertical-metrics.py在 Glyphs 中批量重算垂直度量的脚本checks/FontBakery 生成的逐字体检查报告Markdownnotes/准入过程中的人工 QA 笔记与轮廓复查记录二、环境与前置条件README 将准备阶段拆成两步。1. 准备两个本地仓库并切换到 qa 分支git clone Fira Code 仓库地址 cd firacode git checkout qaREADME 要求切换到qa分支执行整套流程。从当前 master 检出结构看googlefonts-qa/scripts/下只有move-check.sh、requirements.txt、get-version.py、set-vertical-metrics.py并没有 README 中提到的build.sh——可以推断该脚本随qa分支一起维护在 master 分支上只能完成“搬运 检查”的一半流程。另一个前置条件本机必须有一份 google/fonts 仓库的本地克隆。原因是 FontBakery 的检查是面向“位于 google/fonts 仓库目录结构中的字体”设计的因此需要把这个仓库克隆到任意合适位置README 示例是~/yourusername/type_repos之类的父目录下后文move-check脚本会直接在这个目录里操作并建分支。2. 搭建 Python 测试环境virtualenv -p python3 build/venv source venv/bin/activate pip install -U -r googlefonts-qa/scripts/requirements.txt chmod x googlefonts-qa/scripts/build.sh chmod x googlefonts-qa/scripts/move-check.shrequirements.txt 只列了三个 QA 核心依赖fontbakery检查工具、从源码安装的gftoolsGoogle Fonts 工具集、fontmake字体构建器。需要留意两点细节README 中创建虚拟环境的命令是build/venv而激活命令写的是source venv/bin/activate两处路径不一致实际执行时要以自己创建的位置为准move-check.sh内部执行source venv/bin/activate所以虚拟环境最好放在仓库根目录下的venv仓库根目录另有一份 requirements.txt固定了主构建链的版本fontmake3.11.1、glyphsLib6.12.7、gftools0.9.993、fontbakery1.1.0、ufo2ft3.7.0、uharfbuzz0.53.3与 QA 目录下不锁版本的清单相互独立。此外move-check.sh还隐含两个非 Python 依赖ttxFontTools 提供的字体表转储工具和xml sellibxml2 的命令行 XML 查询工具后面源码解析部分会用到它们。三、构建并执行 move-check环境就绪后在 Fira Code 仓库根目录先构建googlefonts-qa/scripts/build.sh构建完成后运行搬运与检查脚本参数为本地 google/fonts 仓库的绝对路径move-check 绝对路径/fontsmove-check.sh 文件头对用法有同样说明从 Fira Code 仓库根目录调用参数指向本地 google/fonts 仓库。脚本对参数为空或--help会打印示例路径并退出。一切顺利时你会得到google/fonts 目录下的本地firacode分支新字体已按ofl/firacode/结构就位每个字体文件对应一份 FontBakery Markdown 检查报告写入googlefonts-qa/checks/README 正文写的是googlefonts-qa/scripts/checks而 move-check.sh 实际创建的是googlefonts-qa/checks/static以脚本为准。四、move-check.sh 源码解析它到底做了什么这个约 90 行的 Bash 脚本是整条流水线的核心按执行顺序可分为五个阶段。1. 从可变字体中提取版本号ttx -t head $firaCodeVF fontVersionv$(xml sel -t --match //*/fontRevision -v value ${firaCodeVF/.ttf/.ttx}) rm ${firaCodeVF/.ttf/.ttx}见 move-check.sh 第 31-33 行$firaCodeVF指向distr/variable_ttf/FiraCode-VF.ttf。脚本先用ttx把该字体的head表反汇编成.ttxXML再用xml sel取出fontRevision属性的值拼成v开头的版本号最后删除临时.ttx。这个版本号最终会写进 git 提交信息让每次 PR 的版本变化可追溯。2. 同步 google/fonts 仓库并重建 firacode 分支cd $gFontsDir git checkout master git pull upstream master git reset --hard git checkout -B firacode git clean -f -d第 38-43 行注意这里假设 google/fonts 克隆配置了名为upstream的远端checkout -B保证分支可重复创建配合reset --hard与clean -f -d使每次运行都从干净的官方 master 状态出发避免上一轮实验残留。3. 复制字体与元数据到 ofl/firacodemkdir -p ofl/firacode cp $firaCodeVF ofl/firacode/FiraCode-Light.ttf mkdir -p ofl/firacode/static statics$(ls $firaCodeDir/distr/ttf/*.ttf) for ttf in $statics do cp $ttf ofl/firacode/static/$(basename $ttf) done第 48-57 行布局是 google/fonts 仓库的标准 OFL 字体目录结构可变字体放顶层静态字重放static/子目录。有个值得注意的细节变量字体在顶层被重命名为FiraCode-Light.ttf——这与 QA-notes.md 中讨论的“可变字体命名规范要求-VF后缀尚在 google/fonts 侧批量推进”的结论相呼应说明当时的命名策略是有意为之的过渡方案。紧接着是三个元数据文件第 62-66 行来源目标说明googlefonts-qa/METADATA.pbofl/firacode/METADATA.pbGoogle Fonts 家族元数据LICENSEofl/firacode/OFL.txt把项目 OFL 许可文本改名为 Google Fonts 约定的文件名googlefonts-qa/gfonts-description.htmlofl/firacode/DESCRIPTION.en_us.htmlGoogle Fonts 展示页描述README 中“修正若干字体元数据以对齐 Google Fonts 标准”一句落到脚本里主要就是这些重命名与落位操作真正的数值型元数据修正如垂直度量发生在更上游的 Glyphs 源文件阶段下一节会讲。4. 逐文件运行 FontBakery 并落盘报告cd ofl/firacode ttfs$(ls -R */*.ttf ls *.ttf) # 静态字体 可变字体 for ttf in $ttfs do fontbakery check-googlefonts $ttf --ghmarkdown $firaCodeQADir/checks/${ttf/.ttf/.checks.md} done第 75-85 行命令行前特意set e第 71 行否则 FontBakery 遇到第一个不通过的字体就以非零码退出脚本会中断导致后续字体的报告缺失。--ghmarkdown把结果写成适合 GitHub 展示的折叠式 Markdown文件名是字体名替换扩展名.checks.md与仓库中现存的 checks/ 目录一一对应如 FiraCode-Regular.checks.md。注释里还保留了只查可变字体或只查静态字体的两条备选命令方便缩小检查范围、加快迭代。5. 提交并强推 PR 分支git add . git commit -m fira code: $fontVersion added. git push --force upstream firacode第 87-90 行每次运行都会把 google/fonts 侧的firacode分支强制刷新为当前构建状态这就是 README 所说“为提交 PR 做准备”的落地方式本地firacode分支随时可作为一个干净的 PR 分支推到官方仓库。五、读懂 FontBakery 检查报告以 FiraCode-Regular.checks.md 为例报告开头声明 FontBakery 版本该报告为 0.7.1随后按检查组如[31] Family checks组织每个检查项带有 FAIL / WARN / INFO / PASS 级别。报告开头就能看到一个典型 FAILCheck font has a license — 未找到许可文件请添加OFL.txt或LICENSE.txt。这条失败恰好说明了检查必须在 google/fonts 目录结构里运行move-check.sh把LICENSE复制为OFL.txt之后该检查项即被满足——检查脚本与搬运脚本是同一个闭环的两半。同一报告中还有大量 PASS 项如同家族字元数一致、等宽数字宽度一致、无不可接受的控字符等它们是“字体家族级健康度”的基线。迭代工作流因此非常直白跑脚本 → 打开checks/*.checks.md→ 定位 FAIL/WARN → 到源文件Glyphs 源、METADATA.pb 或脚本本身修复 → 重新 build → 重跑 move-check。QA-notes.md 记录的就是这个过程中真实遇到的失败项与最终处置。六、从 QA 笔记看真实修复案例QA-notes.md 是准入过程中“检查项 → 修复手段”的完整档案下面挑选有源码级答案的几项展开。检查项FontBakery 检查 ID 见笔记原文失败内容修复手段unitsperem_strictUPM 为 1000官方强烈建议 2000利于变量字体插值精度将 UPM 整体缩放到 2000笔记中已完成name/ascii_only_entriesnameID 0 的版权字符串含非 ASCII 的 © 符号移除 © 符号family/win_ascent_and_descentusWinAscent935要求 ≥1050、usWinDescent265要求 ≥500运行 set-vertical-metrics.py 重算垂直度量varfont_weight_instances存在wght450.0的 Retina 实例要求 100 的倍数给 Retina 实例设自定义参数weightClass: 450、菜单字重 Normal并取消“活动实例”状态避免干扰构建与 Regular 字重usweightclassLight 字体的usWeightClass期望 300 实际 400在源母版上设置Axis Location自定义参数对应 fontmake 的已知问题使导出值跟随默认实例valid_glyphnames多个连字符字形名超过 31 字符上限或含非法字符上游 Fira Code 提 issue暂保留判断对 Web 字体影响有限canonical_filename可变字体用了静态字体命名方式要求-VF后缀等待 Google 侧批量调整命名策略笔记记录为“waiting on others”font_copyright版权声明不匹配官方模板经社区讨论确认现写法可接受并向 FontBakery 提 issue其中垂直度量的修复最能体现“脚本化对齐标准”的思路。set-vertical-metrics.py 是一个 Glyphs 菜单脚本其算法分两层Win 度量取全字体包围盒极值遍历每个字形的所有图层取layer.bounds计算 ascent/descent记录全局最高/最低点第 34-52 行。这解释了为什么失败报告要求usWinAscent ≥ 1050win 度量必须覆盖字体中任何字形实际到达的最高/最低位置。Typo/hhea 度量只取字母极值脚本内置大写字形与小写字形名单含 Fira Code 特有的f_i、s_t等连字名只对名单内字形取极值避免非常用字形把基线间距撑得过大。随后脚本把结果写回各母版的 Glyphs 自定义参数第 94-112 行启用Use Typo MetricswinAscent/winDescent设为包围盒极值typoLineGap与hheaLineGap设为 0typoAscender/Descender、hheaAscender/Descender设为字母极值。脚本头部注释也提醒它假设各母版垂直度量一致套用到度量不同的字体家族前要先自行确认——这就是“把 Google Fonts 度量标准翻译成源文件参数”的具体做法。七、外推母版后的轮廓复查outline-checks.md 记录了准入过程中一个容易被忽略的环节为了让 Fira Code 能通过 FontMake 构建团队外推extrapolation了一个 Light 母版而外推是有用但不完美的工具可能把轮廓错误带入新母版。复查流程是用 Glyphs 的 Red Arrows 扩展定位可疑点再人工甄别拿不准时对照 Bold 母版、对照祖先字体 Fira Mono 的 Regular 母版把现有图层复制为可见的背景图层作为修改参照只修“让设计变得没用的非预期矢量问题”不改设计本身。笔记中列举了多处实际修正/U-cy主干上的非预期弯折、Zhedescender-cy中被外推缩放成 10% 的部件调整为 85%/100% 后形态恢复、Kastroke-cy过粗的横杠、betaSymbol中本不该相交的线条以及asciitilde_greater.liga等连字右侧断开的连接。同时笔记也明确列出了有意保留的小问题横杠上多余的控制点、无害的图形重叠、轻微的曲线反弯——这些不影响渲染留待以后统一处理。这段记录展示了变量字体构建中“母版外推 → 自动检查 人工轮廓复查”这一环节的完整判断标准。八、适用前提与注意事项分支前提build.sh不在当前 master 检出的googlefonts-qa/scripts/中按 README 的流程它随qa分支提供若只在 master 上操作只能执行“搬运 检查”部分。参数与路径move-check的第一个参数是本地 google/fonts 仓库根目录的绝对路径脚本内部会source venv/bin/activate虚拟环境需放在仓库根目录的venv检查报告实际输出到googlefonts-qa/checks/而非 README 正文写的googlefonts-qa/scripts/checks。隐含系统依赖ttxFontTools与xml sellibxml2是脚本提取版本号所必需的缺失时会卡在第一步。版本语境checks/中的报告基于 FontBakery 0.7.1 生成scripts/requirements.txt 未锁定版本今天重装依赖得到的 FontBakery 版本与规则集会更新部分历史 FAIL如可变字体命名后缀规则可能已被上游规则吸收重跑时以新报告为准。占位文件scripts/get-version.py 在当前检出中是空文件属于流程中的占位脚本不承担实际逻辑。整套工具链的价值在于把 Google Fonts 准入这件“标准多、反馈慢”的事压缩成一个可重复执行的循环一次命令完成构建产物搬运、元数据落位与全量检查报告直接可进版本库修复决策与依据QA-notes.md、outline-checks.md也随仓库沉淀下来供后续版本复跑时直接对照。【免费下载链接】FiraCodeFree monospaced font with programming ligatures项目地址: https://gitcode.com/GitHub_Trending/fi/FiraCode创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表