# BST-TIMEOUT: 300 # 27 cases. The payload read is three programs over 4 MB; # # the consumer block is six 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-fbset-modes and 99-usbids. # # liberation-fonts 2.1.5 -- the Liberation TrueType family (Sans, Serif, Mono), # the metric-compatible free substitutes for Arial, Times New Roman and Courier # New. poky meta/recipes-graphics/ttf-fonts/liberation-fonts_2.1.5.bb. # # WHAT THIS IMAGE ACTUALLY INSTALLS, MEASURED, NOT ASSUMED: 12 TTF files # (4,359,164 bytes) under /usr/share/fonts/ttf, ONE fontconfig alias fragment at # /etc/fonts/conf.d/30-liberation-aliases.conf, and the LICENSE under # /usr/share/doc/liberation-fonts. Fourteen files, all in a single binary # package -- the recipe sets `PACKAGES = "${PN}"`, so there is no -doc or -dev # split for the payload to hide in. That was the ticket's stated packaging risk # and it is discharged by construction rather than by hope. # # THE TICKET NAMES THE WRONG PATH, AND THE SUITE RECORDS THE CORRECTION. # BRINTOS-1339 asks for /usr/share/fonts/truetype/liberation. That is the Debian # layout; this recipe installs to ${datadir}/fonts/ttf and no bbappend here # rewrites it. So the manifest is written against the real path and # `no-debian-fontpath` asserts the Debian one is ABSENT -- a correction that a # future silent move would trip over, rather than a remark in a design doc # nobody re-reads. # # THE REFERENCE IS UPSTREAM'S OWN BYTES, WHICH IS STRONGER THAN AN x86-64 BUILD. # The ticket asks that each file match "the reference the same recipe version # produces on x86-64". It does, and the reason needs no second build: the recipe # is `inherit allarch` and its do_install is a loop of `install -m 0644` over the # extracted tarball, so nothing arch-dependent touches a byte. Every one of the # 12 TTFs was verified byte-identical to liberation-fonts-ttf-2.1.5.tar.gz -- # whose sha256 the recipe itself pins as 7191c669...f25d0 -- and the alias conf # byte-identical to poky's own source file. data/liberation-fonts-manifest.txt # carries those digests and was GENERATED from the built package, not typed. # # TWO LAYERS, AND A RED IN THE FIRST LOCALISES A RED IN THE SECOND: # # file-*, ttf-* the payload arrived intact -- size, bytes, mode, type, # count, and no thirteenth file. No fontconfig involved. # fc-* fontconfig, already on this image, can actually SEE and # RESOLVE it: the cache rebuilds, fc-list finds all twelve # faces and all three families, the alias fragment is # LOADED, and each generic alias resolves to its own family. # # WHY BOTH fc-conflist AND fc-match. These fonts are the ONLY ones on this image, # so `fc-match sans-serif` would return a Liberation face even if the alias # fragment had never been installed -- the case would pass while asserting # nothing about the fragment. fc-conflist answers the question directly by # listing the configuration files fontconfig actually LOADED, and fc-match then # says the mapping is not merely loaded but effective, and maps each generic to # its OWN family rather than to whichever face sorted first. # # WRITTEN TO EXEC AS LITTLE AS POSSIBLE -- one find, one sha256sum and one gawk # cover the entire payload, and the six 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=liberation-fonts # THE CANARY, which asserts nothing about liberation-fonts. # # 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/liberation-fonts-manifest.txt TTFDIR=/usr/share/fonts/ttf CONF=/etc/fonts/conf.d/30-liberation-aliases.conf LIC=/usr/share/doc/liberation-fonts/LICENSE tmp=${TMPDIR:-/tmp} W=$tmp/bst-liberation-fonts.$$ 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 the payload AND over the Debian path the ticket named, so its # 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 "$TTFDIR" "$CONF" "$LIC" /usr/share/fonts/truetype \ -maxdepth 1 -printf '%p %y %s %m %l\n' 2>/dev/null | LC_ALL=C sort > "$W.inv" # One sha256sum over all fourteen. The glob is the shell's, so this is one exec # whatever the file count. # # Liberation*.ttf, NOT *.ttf: ttf-bitstream-vera installs ten more faces into the # same directory (BRINTOS-1449), and an unscoped glob would digest all 22 and # report `sums-ran` red for a file this package does not own. sha256sum "$TTFDIR"/Liberation*.ttf "$CONF" "$LIC" > "$W.sums" 2>&1 LC_ALL=C gawk -v REF="$REF" -v SUMS="$W.sums" -v INV="$W.inv" \ -f "$D/liberation-fonts-verify.awk" "$REF" "$W.sums" "$W.inv" # --------------------------------------------------------- the consumer block # fontconfig is a Depends of this package (the recipe inherits fontcache, which # appends fontconfig-utils to 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 liberation-fonts 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, and MEASURED on the # resulting image this suite parked here -- reaching 24 of its 25 cases against # a full run on the same base pin without the port. 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 -- fc-cache runs and # returns 0. # # 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; the parsing below is shell builtins. fc-list : file family > "$W.list" 2>&1 _faces=0; _sans=0; _serif=0; _mono=0; _foreign=0 while IFS= read -r l; do case "$l" in "$TTFDIR"/Liberation*) _faces=$((_faces+1)) ;; /*) _foreign=$((_foreign+1)); continue ;; *) continue ;; esac # THE FAMILY TALLIES BELOW COUNT ONLY THIS PACKAGE'S OWN FACES, AND THE # `continue` ABOVE IS WHAT MAKES THAT TRUE (BRINTOS-1721). They used to run for # every absolute path fc-list returned, which was correct while this package # was the only Liberation on the image. meta-oe's ttf-liberation 0.2 is now # installed too -- twelve faces carrying these same three family strings, in # /usr/share/fonts/truetype -- so the unscoped form reads 8 and reports a green # port as three reds here. Scoped rather than re-based to 8: what THIS package # can honestly assert is its OWN four-per-family style set, and a count of 8 # would go stale again the moment either package changed. 99-ttf-liberation # counts its twelve from its own side, so the interaction stays visible. case "$l" in *"Liberation Sans"*) _sans=$((_sans+1)) ;; esac case "$l" in *"Liberation Serif"*) _serif=$((_serif+1)) ;; esac case "$l" in *"Liberation Mono"*) _mono=$((_mono+1)) ;; esac done < "$W.list" # All twelve faces are DISCOVERABLE, not merely present on disk. A cache that # serialised wrongly, or a FreeType that refused the outlines, shows up here as # a count below twelve while every file-* case above stays green -- which is the # split that says where to look. # # MATCHED ON Liberation* AND NOT ON THE DIRECTORY, for the same reason the awk's # census is: ttf-bitstream-vera installs ten more faces into ${datadir}/fonts/ttf # (BRINTOS-1449), and a pattern of "$TTFDIR"/* would count them and report 22. if [ "$_faces" -eq 12 ]; then bst_ok $S/fc-list-faces else bst_notok $S/fc-list-faces "fc-list reports $_faces faces under $TTFDIR, want 12"; fi # The three families, four faces each (Regular, Bold, Italic, BoldItalic). for pair in "sans:$_sans" "serif:$_serif" "mono:$_mono"; do nm=${pair%%:*}; n=${pair#*:} if [ "$n" -eq 4 ]; then bst_ok "$S/fc-family-$nm" else bst_notok "$S/fc-family-$nm" "fc-list reports $n faces for the $nm family, want 4"; fi done # THE ALIAS FRAGMENT IS LOADED. Asked directly rather than inferred from a match: # these are the only fonts on this image, so a match would answer "Liberation" # whether or not the fragment had ever been installed. # A `+` line is a file fontconfig LOADED; a `-` line is one merely available # under conf.avail. The path is matched inside the line rather than anchored # immediately after the "+ ", because fc-conflist appends a description field # and the exact spacing is its business, not this suite's. fc-conflist > "$W.conf" 2>/dev/null _loaded=0 while IFS= read -r l; do case "$l" in "+ "*"$CONF"*) _loaded=1 ;; esac done < "$W.conf" if [ "$_loaded" -eq 1 ]; then bst_ok $S/fc-conf-loaded else bst_notok $S/fc-conf-loaded "fc-conflist does not list $CONF among the loaded (+) configuration files"; fi # ...and it is EFFECTIVE, and maps each generic to its OWN family rather than to # whichever face happened to sort first. # # monospace IS NO LONGER OURS, AND IT HAS NOW CHANGED HANDS TWICE WITHOUT THIS # PORT MOVING. Liberation Mono answered this generic originally, only through # 30-metric-aliases.conf binding it to Courier New at rank 5 in fontconfig's own # 60-latin.conf ranking # # Noto Sans Mono, DejaVu Sans Mono, Inconsolata, Andale Mono, Courier New, ... # # on which Liberation Mono does not appear at all. ttf-inconsolata (BRINTOS-1451) # then put a rank-3 family on the image and took it on MERIT. source-code-pro- # fonts (BRINTOS-1455) has now taken it from Inconsolata by a different route # again -- its recipe ships /etc/fonts/conf.d/44-source-code-pro-fonts- # fontconfig.conf, whose for the monospace alias sorts before 60-latin # and so prepends Source Code Pro ahead of the whole ranked list. # # THE CASE IS AMENDED, NOT DELETED, AND FOR THE SAME REASON THE FIRST TIME: what # it is worth is that the generic resolves to the family the configuration # actually selects, and it is still that, from the other side. 99-source-code- # pro-fonts' own fc-match-monospace asserts it positively and 99-ttf-inconsolata # now asserts it from the losing side, so a disagreement between the three suites # is visible rather than silent. # # AND ttf-tlwg (BRINTOS-1729) HAS NOW TAKEN THE OTHER TWO, BY THE SAME ROUTE AS # source-code-pro-fonts AND FOR THE SAME REASON. Its do_install:append ships ten # fragments into /etc/fonts/conf.d at 64; PREPENDS ahead # of the generic while THIS file's only APPENDS behind it, so Kinnari # takes serif and Waree takes sans-serif. Where two tlwg fragments compete for one # generic the FIRST loaded wins, because each later one prepends ahead of the # generic and behind its predecessor -- 64-01 over 64-02 for serif, 64-11 over # 64-12/13/14/15 for sans-serif. Measured at fontconfig 2.15.0 against this # image's own font tree, with and without the package. # # SO THIS SUITE NOW OWNS NONE OF THE THREE, AND THE CASES ARE STILL AMENDED # RATHER THAN DELETED, FOR THE THIRD TIME AND THE SAME REASON: what they are # worth is that each generic resolves to the family the configuration actually # selects, and they still say that. 99-ttf-tlwg asserts serif and sans-serif # positively, 99-source-code-pro-fonts asserts monospace positively, and # 99-ttf-gentium and 99-ttf-inconsolata assert theirs from the losing side. # # The alias fragment this block exists to prove is now proven by fc-conf-loaded # above alone -- which is what that case is for, and why it was written to ask # fontconfig directly rather than to infer the fragment from a match result. for pair in "sans-serif:Waree" "serif:Kinnari" "monospace:Source Code Pro"; do gen=${pair%%:*}; want=${pair#*:} _out=$(fc-match "$gen" 2>&1) case "$_out" in *"$want"*) bst_ok "$S/fc-match-$gen" ;; *) bst_notok "$S/fc-match-$gen" "fc-match $gen => '$(_bst_1line "$_out")', want $want" ;; esac done rm -f "$W.inv" "$W.sums" "$W.cache" "$W.list" "$W.conf" 2>/dev/null