This page documents the gotta-patch-em-all-font-patcher!.sh script, which automates running font-patcher across every source font in the repository. It covers font discovery, filtering, parallel execution, timestamp preservation, and the fontfilenames manifest format.
For documentation on the individual font-patcher command and its options, see Patching Options. For Docker-based patching, see Docker Usage.
bin/scripts/gotta-patch-em-all-font-patcher!.sh is the top-level batch driver for producing all official patched fonts. It:
src/unpatched-fonts/font-patcher three times per source file (standard, mono, propo variants)patched-fonts/Prerequisites: Bash ≥ 4 and fontforge must be on PATH. The --keeptime option additionally requires ttfdump.
Diagram: Batch Processing Pipeline
Sources: bin/scripts/gotta-patch-em-all-font-patcher!.sh388-468
| Short | Long | Effect |
|---|---|---|
-c | --checkfont | Write output to check-fonts/ instead of patched-fonts/ |
-t | --keeptime | Preserve timestamp from the existing patched font |
-v | --verbose | Print the full fontforge command before running it |
-i | --info | Regenerate READMEs only; skip all patching |
-j | --jobs | Run up to 8 patch processes in parallel |
-h | --help | Print usage |
A single optional positional FILTER argument may follow the options. See Filtering below.
Sources: bin/scripts/gotta-patch-em-all-font-patcher!.sh57-80
The script uses find on src/unpatched-fonts/ to collect all files ending in .ttf, .otf, or .sfd into the source_fonts array.
source_fonts_dir="${repo_root_dir}/src/unpatched-fonts"
Results are collected using a null-delimited read loop to handle filenames containing spaces correctly.
Sources: bin/scripts/gotta-patch-em-all-font-patcher!.sh173-193
A single FILTER argument controls which fonts are processed. The leading character determines the filter mode:
| Argument form | Behavior | Example |
|---|---|---|
iosevka | Matches font filenames containing the string | processes all *iosevka*.ttf/otf/sfd files |
/iosevka | Matches font files under a directory whose path contains the string | processes all files under any path with iosevka in it |
When no filter is given, all fonts under src/unpatched-fonts/ are processed.
Purge logic: When a filter matches all fonts in a source directory (or no filter is applied), the corresponding output directory is purged before patching to remove stale files from previous naming conventions. Purging is skipped when the filter selects only a subset of files from a directory.
Sources: bin/scripts/gotta-patch-em-all-font-patcher!.sh147-171 bin/scripts/gotta-patch-em-all-font-patcher!.sh388-432
patch_font)Diagram: patch_font function internals
For each source font file, patch_font is called with the file path, its array index, and a purge flag. It:
ttfdump (see Timestamp Preservation)src/unpatched-fonts with patched-fonts in the pathconfig.cfg in the font's directory, its parent, or the font rootfontforge -script font-patcher three times:
-s): produces a "Nerd Font Mono" variant--variable): produces a "Nerd Font Propo" variantThe NERDFONTS environment variable is appended to each invocation, allowing extra patcher flags to be injected without modifying the script.
Sources: bin/scripts/gotta-patch-em-all-font-patcher!.sh217-331
When the -j / --jobs flag is set, each patch_font call is launched as a background process:
patch_font "${source_fonts[$i]}" "$i" "$purge_destination" 2>/dev/null &
To prevent runaway process counts, a wait is issued every max_parallel_process (default: 8) iterations. A final wait after the loop ensures all background jobs complete before info generation begins.
| Variable | Value | Purpose |
|---|---|---|
max_parallel_process | 8 | Maximum concurrent patch_font background jobs |
parallel | TRUE / unset | Controls whether & is appended to the call |
Info generation (generate_info) always runs sequentially, after all patching is complete.
Sources: bin/scripts/gotta-patch-em-all-font-patcher!.sh38 bin/scripts/gotta-patch-em-all-font-patcher!.sh433-457
--keeptime)When --keeptime is active, the script reads the modified field from the head table of an existing patched font using ttfdump, converts it from the Mac epoch (January 1, 1904) to Unix epoch via dc, and exports the result as SOURCE_DATE_EPOCH. This causes font-patcher to embed that same timestamp in the newly patched font, making re-patches produce the same modification time as the prior release.
The conversion formula used:
SOURCE_DATE_EPOCH=$(dc -e "16i ${orig_font_date} Ai 86400 24107 * - p")
where 24107 is the number of days between the Mac epoch (1904-01-01) and Unix epoch (1970-01-01).
ttfdump must be installed; the script exits with an error if it is missing.
Sources: bin/scripts/gotta-patch-em-all-font-patcher!.sh40-46 bin/scripts/gotta-patch-em-all-font-patcher!.sh222-254
SOURCE_DATE_EPOCHSOURCE_DATE_EPOCH is a reproducible-builds.org standard environment variable. The script handles it as follows:
SOURCE_DATE_EPOCH is already set in the environment, it is used as-is.fontforge processes inherit it.This means all fonts patched in a single batch run share the same embedded timestamp, unless --keeptime overrides it per-font.
Both GNU date (-R --date=@EPOCH) and BSD date (-r EPOCH) are supported for converting the epoch to a human-readable string for log output.
Sources: bin/scripts/gotta-patch-em-all-font-patcher!.sh198-215
generate_info)After all patching completes, the script iterates the source_fonts array a second time and calls generate_info for each font. This function:
standardize-and-complete-readmes.sh once per unique font root directory (tracked via the last_font_root variable)copy_license to copy all license and OFL files from the source font's tree into the patched output directorygenerate_info is always run sequentially to avoid race conditions with background processes.
Sources: bin/scripts/gotta-patch-em-all-font-patcher!.sh336-366 bin/scripts/gotta-patch-em-all-font-patcher!.sh460-468
fontfilenames Manifestsrc/unpatched-fonts/fontfilenames is a plain-text file listing one representative font file per font family — specifically the Regular weight used for image preview generation. Each line is a path relative to src/unpatched-fonts/, with spaces in filenames escaped with a backslash.
0xProto/0xProto-Regular.ttf
AnonymousPro/Regular/Anonymous\ Pro.ttf
Meslo/M/Regular/Meslo\ LG\ M\ Regular\ for\ Powerline.ttf
...
This file is not read by gotta-patch-em-all-font-patcher!.sh directly. Its primary use is as an input for tooling that needs a single specimen per family, e.g.:
Regenerating fontfilenames: The file is derived from the imagePreviewFontSource field in bin/scripts/lib/fonts.json using jq, filtered to exclude .sfd files, and sorted case-insensitively:
For details on the fonts.json schema and the imagePreviewFontSource field, see fonts.json Schema.
Sources: src/unpatched-fonts/fontfilenames1-70 src/unpatched-fonts/README.md1-20
Diagram: Source-to-Output Path Mirroring
The output path is computed by simple string replacement inside patch_font:
patched_font_dir="${f%/*}/"
patched_font_dir="${patched_font_dir/$unpatched_parent_dir/$patched_parent_dir}"
The --checkfont flag substitutes check-fonts for patched-fonts as the value of patched_parent_dir.
Sources: bin/scripts/gotta-patch-em-all-font-patcher!.sh256-261 bin/scripts/gotta-patch-em-all-font-patcher!.sh48-50
| Variable | Set by | Purpose |
|---|---|---|
SOURCE_DATE_EPOCH | Script (if unset) or caller | Timestamp embedded in all patched fonts |
NERDFONTS | Caller | Extra flags appended to every font-patcher invocation |
parallel | -j flag | Enables background (&) execution of patch_font |
keeptime | -t flag | Enables per-font timestamp preservation via ttfdump |
info_only | -i flag | Skips patching; runs only generate_info |
verbose | -v flag | Prints full fontforge commands before execution |
Sources: bin/scripts/gotta-patch-em-all-font-patcher!.sh1-10 bin/scripts/gotta-patch-em-all-font-patcher!.sh296-325
Refresh this wiki
This wiki was recently refreshed. Please wait 3 days to refresh again.