# BST-TIMEOUT: 300 # 43 cases. The payload read is three programs over 1 MB in # # 256 files; the consumer block is four more execs at # # roughly 1.5 s apiece on this arm, and fc-cache walks the # # whole font set. Same value and reason as # # 99-liberation-fonts and 99-usbids. # # terminus-font 4.49.1 -- Terminus, the clean fixed-width bitmap face designed # for long (8+ hours a day) terminal work. # meta-openembedded/meta-oe/recipes-graphics/terminus-font/terminus-font_4.49.1.bb. # # WHAT THIS IMAGE ACTUALLY INSTALLS, MEASURED, NOT ASSUMED: 256 files in two # packages -- 238 .psf.gz console fonts under /usr/share/consolefonts (597,377 # bytes, terminus-font-consolefonts) and 18 .pcf.gz X11 bitmaps under # /usr/share/fonts/terminus (466,125 bytes, terminus-font-pcf). Nine pixel sizes # (12 14 16 18 20 22 24 28 32) in two weights. # # ONE OF THE TWO DIRECTORIES IS SHARED, AND THE STAGED ROOTFS IS WHAT SAID SO. # /usr/share/fonts/terminus is this package's own and holds exactly its 18 files. # /usr/share/consolefonts holds 240, not the 238 shipped here: cmatrix 2.0, on # this image far longer, puts matrix.fnt and matrix.psf.gz there. A pkgdata sweep # says those two packages are the only writers. The names are disjoint (ter-* # against matrix.*), so nothing is overwritten -- which is the ticket's "must not # claim a path another recipe already owns", answered by measurement. The # console-font cases are therefore scoped to this package's OWN ter-* namespace: # a foreign ter-* file, which WOULD shadow ours, is still a red, while an # unrelated port dropping a file into the shared directory is not. # # THE PACKAGING RISK THE TICKET NAMED IS REAL HERE, WHICH IS UNUSUAL. This recipe # puts every byte into a SUBPACKAGE, so the main ${PN} package is empty and # terminus-font_4.49.1-r0_all.deb is never written at all -- measured from the # as-is build before any bbappend existed, which produced only # terminus-font-consolefonts and two empty -dbg/-dev. So the obvious # `IMAGE_INSTALL += "terminus-font"` would have ended do_rootfs with "Unable to # find package"; the image names the two subpackages instead. `no-empty-pn-path` # below keeps that a measurement: if /usr/share/terminus-font ever appears, the # main package has stopped being empty and the IMAGE_INSTALL lines need revisiting. # # THE PCF HALF EXISTS ONLY BECAUSE OF A BBAPPEND, AND WITHOUT IT THE PORT WOULD # BE UNVERIFIABLE END TO END. The recipe gates its X11 output on a PACKAGECONFIG # defaulted from DISTRO_FEATURES, and this distro sets DISTRO_FEATURES = "" -- # so stock, only the console fonts are built. That matters because PSF is not a # format FreeType reads: fontconfig can see nothing of Terminus through # /usr/share/consolefonts, which is not under /usr/share/fonts and would not be # scanned even if it could. terminus-font_%.bbappend sets PACKAGECONFIG = "x11". # # THE TICKET CALLS THIS A DATA-ONLY PACKAGE THAT COMPILES NOTHING, AND THE SUITE # RECORDS THE CORRECTION. It does compile: a hand-written do_configure and a # do_compile running `oe_runmake psf pcf` generate the fonts from BDF sources. # What is true, and is what makes the x86-64 reference the ticket asks for # answerable without a second build, is that every tool doing so is NATIVE # (hostperl-runtime-native, gzip-native, bdftopcf-native) -- so `inherit allarch` # is honest and no wasm32 compiler touches a byte. The gzip wrapper is # deterministic BY PATCH: use-no-name-option-for-gzip.patch adds -n to every gzip # call in the Makefile, and the built payload was checked rather than trusted -- # both a .psf.gz and a .pcf.gz open `1f 8b 08 00 00 00 00 00 00 03`, FLG 0x00 and # MTIME 0. data/terminus-font-manifest.txt was GENERATED from the built packages. # # TWO LAYERS, AND A RED IN THE FIRST LOCALISES A RED IN THE SECOND: # # pcf-*, psf-* the payload arrived intact -- size, bytes, mode, type, # count, and no extra file. No fontconfig involved. # fc-* fontconfig, already on this image, can actually SEE and # RESOLVE it: the cache rebuilds, fc-list finds all 18 # faces under the family "Terminus" with all nine pixel # sizes, and fc-match selects the RIGHT SIZE's file -- # which is the one property a bitmap family has that a # scalable one does not. # # WRITTEN NOT TO DEPEND ON WHICH OTHER FONTS ARE INSTALLED. liberation-fonts # landed on this image one ticket earlier and ships an alias fragment binding # the generic families, so a case asserting `fc-match monospace` would be # asserting the outcome of a CONTEST between two ports rather than anything # about either -- and would go red or green depending on which landed last. # Every case here names Terminus's own family or its own directory. # # WRITTEN TO EXEC AS LITTLE AS POSSIBLE -- one find, one gawk|sha256sum pipeline # and one gawk cover all 256 payload files, and the five remaining execs all # belong to the consumer block, where each one IS the measurement. On this arm a process's # memory is not returned when it exits and /bin/sh is a 16 MB wasm module, so a # suite's cost is dominated by how many programs it starts. . "$BST_LIB" S=terminus-font # THE CANARY, which asserts nothing about terminus-font. # # A suite's FIRST BST result line is lost between the guest's printf and the # host's read -- per-suite, deterministic, and NOT a defect in the host tool # (BRINTOS-1149 established that and filed it as linux-in-the-browser#177). # The harness reports the deficit but computes its pass count as # total-minus-failures, so THE DROPPED LINE IS COUNTED AS A PASS. A nothing-case # therefore stands in that position and the eaten line costs nothing; every real # case below is still counted. It sits ahead of the `require` guards # deliberately, because a `require` that skips would emit its skip as the first # line and that line would be eaten too. # # Remove this case when linux-in-the-browser#177 is fixed. bst_ok $S/suite-canary D=$BST_DATA REF=$D/terminus-font-manifest.txt PCFDIR=/usr/share/fonts/terminus PSFDIR=/usr/share/consolefonts # the family fontconfig reports on THIS image -- see the fc-match block below FAM=Terminus tmp=${TMPDIR:-/tmp} W=$tmp/bst-terminus-font.$$ require gawk $S/gawk-present require sha256sum $S/sha256sum-present require find $S/find-present if [ ! -f "$REF" ]; then bst_notok $S/ref-present "the reference manifest $REF did not ship" exit 0 fi bst_ok $S/ref-present # ------------------------------------------------------------- payload shape # One find over both payload directories AND over the two paths this port must # NOT have produced, so their absence is a measurement from the same pass. %y # catches a symlink where a regular file is meant and %m the mode -- neither of # which `test -f` can see. find "$PCFDIR" "$PSFDIR" /usr/share/consoletrans /usr/share/terminus-font \ -maxdepth 1 -printf '%p %y %s %m %l\n' 2>/dev/null | LC_ALL=C sort > "$W.inv" # THE DIGESTS COME FROM `sha256sum -c` READING THE MANIFEST DOWN A PIPE, NOT # FROM A GLOB ON THE COMMAND LINE. That is not a style preference. The guest's # argument buffer __wasm32_args_buf is 8192 bytes and an exec that exceeds it # WEDGES rather than errors -- no case is emitted and the suite is reported # INCOMPLETE with no cause. Naming these 256 files by absolute path builds a # 10,286-byte argv, and the first version of this suite did exactly that and # wedged two consecutive boots (brintos/hardwarejs#15; the packager README # carries the rule and 99-cim-schema-final's 95,410-byte argv as the precedent). # A pipeline puts nothing on the argv however many files the manifest names. # # It also reads better than the glob it replaces: the manifest IS the file list, # so this cannot drift from it, and `: OK|FAILED` per file is what the # verifier wants anyway. The gawk on the left is the same one-liner the README # suggests, turning " " into sha256sum's check format. LC_ALL=C gawk '!/^#/ && NF == 3 { print $2 " " $3 }' "$REF" \ | sha256sum -c > "$W.sums" 2>&1 LC_ALL=C gawk -v REF="$REF" -v SUMS="$W.sums" -v INV="$W.inv" \ -f "$D/terminus-font-verify.awk" "$REF" "$W.sums" "$W.inv" # --------------------------------------------------------- the consumer block # fontconfig-utils is a Depends of terminus-font-pcf (the recipe inherits # fontcache, which puts the pcf package in FONT_PACKAGES and appends # fontconfig-utils to its RDEPENDS) and is already on this image. Its ABSENCE is # therefore a real defect in this port, not a legitimate skip -- a `require` # here would report the port green on an image where nothing can read the fonts # it just installed. if [ ! -x /usr/bin/fc-list ]; then bst_notok $S/fc-utils-present "fontconfig-utils is a Depends of terminus-font-pcf but /usr/bin/fc-list is absent" rm -f "$W.inv" "$W.sums" exit 0 fi bst_ok $S/fc-utils-present # THE CACHE IS REBUILT HERE RATHER THAN ASSUMED. Maintainer scripts do not run # at rootfs assembly on this arm (no wasm32 qemu-user), so the fontcache class's # postinst is deferred to run-postinsts at first boot. Forcing the rebuild makes # every case below independent of whether that had already happened, which is # also exactly what the ticket asks for. # `fc-cache`, NOT `fc-cache -f`, SINCE BRINTOS-1725. The -f rebuilt every # directory whether or not its cache was valid, which means mapping every face on # the image; a file-backed mapping above roughly 578 kB is REFUSED over the cloud # FUSE bridge and the caller PARKS, beyond SIGKILL (linux-in-the-browser#165, # bracketed by BRINTOS-1450). Before ttf-pt-sans the image's largest face was # Ubuntu-L.ttf at 415,552 bytes, under the bracket, and this call was harmless; # that port adds four faces above it, the largest 584,812. # # THIS SUITE WAS NOT ITSELF MEASURED PARKING, and that is worth stating rather # than implying. Four of its peers were, on the ported image, each reaching its # consumer block and dying at the 600 s bound -- 99-cantarell-fonts at 43 of 50, # 99-ttf-gentium at 47 of 55, 99-source-code-pro-fonts at 86 of 96 and # 99-liberation-fonts at 24 of 25 -- against 50/50 and 55/55 for the first two on # the same base pin without the port. This suite makes the same call over the # same font set, so it is amended by the same rule. Without -f, fc-cache rebuilds # only what is stale, and nothing is: /var/cache/fontconfig ships populated, and # `fc-cache` returns 0 in 3 s on that image where `timeout -k 5 150 fc-cache -f` # never returned. The case still asserts what it always did. # # BRINTOS-WORKAROUND: linux-in-the-browser#165 revisit -- drop -f so only a stale # cache is rebuilt; it goes back in when the mmap population path tolerates a # parking read. fc-cache > "$W.cache" 2>&1 _rc=$? if [ "$_rc" -eq 0 ]; then bst_ok $S/fc-cache-rc else bst_notok $S/fc-cache-rc "fc-cache exited $_rc: $(_bst_1line "$(cat "$W.cache")")"; fi # ONE fc-list for the whole consumer read -- file, family and pixelsize in a # single call; the parsing below is shell builtins. Lines read # /usr/share/fonts/terminus/ter-x16n.pcf.gz: xos4 Terminus:pixelsize=16 fc-list : file family pixelsize > "$W.list" 2>&1 _faces=0; _fam=0; _sizes="" while IFS= read -r l; do case "$l" in "$PCFDIR"/*) ;; *) continue ;; esac _faces=$((_faces+1)) # ANCHORED ON ": " SO THE PATH CANNOT SATISFY IT. Every one of these lines # contains the string "terminus" in its directory component, so a bare # *Terminus* would be green whatever fontconfig reported. fc-list's format is # ": :pixelsize=", so the family field is the one that # follows ": ". case "$l" in *": $FAM:"*|*": $FAM") _fam=$((_fam+1)) ;; esac _px=${l##*pixelsize=} case "$_px" in ''|*[!0-9.]*) ;; *) _px=${_px%%.*} case " $_sizes " in *" $_px "*) ;; *) _sizes="$_sizes $_px" ;; esac ;; esac done < "$W.list" # All 18 faces are DISCOVERABLE, not merely present on disk. A cache that # serialised wrongly, or a FreeType built without the PCF driver or without the # gzip wrapper, shows up here as a count below 18 while every pcf-* case above # stays green -- which is the split that says where to look. if [ "$_faces" -eq 18 ]; then bst_ok $S/fc-list-faces else bst_notok $S/fc-list-faces "fc-list reports $_faces faces under $PCFDIR, want 18"; fi # ...and all 18 under ONE family. The name carries upstream's xos4 foundry # prefix, which is what fontconfig reports and is not the bare "Terminus" a # reader would guess. if [ "$_fam" -eq 18 ]; then bst_ok $S/fc-list-family else bst_notok $S/fc-list-family "$_fam of $_faces faces report family '$FAM', want 18"; fi # THE NINE PIXEL SIZES ARE THE POINT OF A BITMAP FAMILY. A scalable font has one # face per style and fontconfig derives every size from it; here each size is a # separate file that had to survive generation, gzip, packaging and the cache. _want="12 14 16 18 20 22 24 28 32" _got=$(for s in $_sizes; do echo "$s"; done | sort -n | tr '\n' ' ') _got=${_got% } if [ "$_got" = "$_want" ]; then bst_ok $S/fc-list-pixelsizes else bst_notok $S/fc-list-pixelsizes "fc-list reports pixelsizes '$_got', want '$_want'"; fi # THE FAMILY IS "Terminus", AND ONLY THE TARGET COULD SETTLE THAT. # # fc-match ALWAYS returns a face -- it never fails -- so on an image carrying one # font every family name "matches", and a case asserting one would be green # without asserting anything. This image carries liberation-fonts as well, so the # question is real here: a wrong family falls through to Liberation Mono, which # is exactly what this suite's first on-target run reported. # # THE HOST AND THE TARGET DISAGREE ABOUT WHAT THE FAMILY IS CALLED, and the host # is the one that is unusual. Upstream's BDFs carry FOUNDRY xos4. A desktop # fontconfig folds that into the family string and answers "xos4 Terminus"; the # fontconfig 2.15.0 on this image keeps them apart. Measured on target: # # fc-scan %{family}|%{foundry} -> Terminus|xos4 # fc-list : file family -> .../ter-x12b.pcf.gz: Terminus # fc-match "Terminus" -> ter-x12n.pcf.gz [Terminus] # fc-match "xos4 Terminus" -> LiberationMono-Regular.ttf [Liberation Mono] # # A host pre-flight of this suite asserted the xos4 spelling and passed; the # target reddened all four fc-* cases. The name below is the target's, which is # the only one that governs -- and because Liberation is installed alongside, # matching "Terminus" and getting Terminus is a real match rather than a fallback. _out=$(fc-match --format '%{file} %{family}\n' "$FAM" 2>&1) case "$_out" in "$PCFDIR"/ter-*.pcf.gz*"$FAM"*) bst_ok $S/fc-match-family ;; *) bst_notok $S/fc-match-family "fc-match '$FAM' => '$(_bst_1line "$_out")', want a $PCFDIR/ter-*.pcf.gz of family '$FAM'" ;; esac # ...AND THE RIGHT SIZE'S FILE COMES BACK, which is the one read that could not # be satisfied by a single face: each size is its own file that had to survive # generation, gzip, packaging and the cache. A cache holding the family but not # the per-size metrics answers both of these with ter-x12n, the first face -- # which is why the two sizes asked for are neither the first nor adjacent to it. for px in 16 28; do _out=$(fc-match --format '%{file}\n' "$FAM:pixelsize=$px" 2>&1) if [ "$_out" = "$PCFDIR/ter-x${px}n.pcf.gz" ]; then bst_ok "$S/fc-match-pixelsize-$px" else bst_notok "$S/fc-match-pixelsize-$px" "fc-match '$FAM:pixelsize=$px' => '$(_bst_1line "$_out")', want $PCFDIR/ter-x${px}n.pcf.gz"; fi done rm -f "$W.inv" "$W.sums" "$W.cache" "$W.list" 2>/dev/null