# BST-TIMEOUT: 300 # 68 cases. MEASURED at elapsed=37s on a fresh guest # # (2026-08-29, local runner, unloaded host, load 0.46, # # peak host RSS 2,187 MiB). Set from the ==BST-SUITE # # elapsed= line, not guessed. 8x the measurement, the same # # bound 99-ttf-ubuntu-font-family carries for the same # # reason: this suite runs no freetype probe, so its cost is # # one fc-scan over eight faces plus a handful of cache # # reads, and a hung suite should cost five minutes of a # # sweep rather than ten. # # # # THE BOUND IS NOT WHAT PROTECTS THIS SUITE, and the two # # blocks below say why: the two calls that can hang here # # PARK rather than run long, and a park survives SIGKILL # # (linux-in-the-browser#165), so neither this marker nor a # # `timeout` around the call can reclaim one. What protects # # it is that neither call is made in the parking form. # # ttf-pt-sans 1.1 -- ParaType's PT Sans, under the ParaType Free Font Licence 1.3. # meta-openembedded meta-oe/recipes-graphics/ttf-fonts/ttf-pt-sans_1.1.bb. # # THE TICKET IS WRONG ABOUT THE INSTALL PATH, AND THAT IS THE FIRST THING TO SAY. # It asks for "the expected font files installed under ${datadir}/fonts/truetype/ # with the file list pinned exactly". They are not there and never were: this # recipe does not `require ttf.inc`, it carries its own do_install, and that # do_install writes ${D}${prefix}/share/fonts/X11/TTF. The path in the ticket is # the round's other ports' path, inherited by assumption. Everything below asserts # the path the recipe actually uses, measured off the built .deb. # # That is not a technicality -- it is the reason this port needs no amendment # anywhere else. /usr/share/fonts/X11 is created by this package and shared with # nothing: no other recipe in meta-oe's ttf-fonts directory installs there, and # the two directories that ARE shared, /usr/share/fonts/ttf and # /usr/share/fonts/truetype, are untouched. 99-cantarell-fonts' WANT_COT1 and # WANT_COT2 therefore do not move for this port, unlike every other font port in # this round. # # WHAT THIS IMAGE ACTUALLY INSTALLS, MEASURED OFF THE BUILT PACKAGE, NOT ASSUMED: # EIGHT files in ONE package, and no -doc package anywhere. # # FILES_INFO:ttf-pt-sans {"/usr/share/fonts/X11/TTF/PTC55F.ttf": 417320, # ".../PTC75F.ttf": 415060, ".../PTN57F.ttf": 437160, # ".../PTN77F.ttf": 584812, ".../PTS55F.ttf": 505376, # ".../PTS56F.ttf": 454336, ".../PTS75F.ttf": 553132, # ".../PTS76F.ttf": 401644} # PKGSIZE:ttf-pt-sans 3768840 # # `PACKAGES` is the default list, so ${PN}-dbg and ${PN}-dev exist and are empty # (ALLOW_EMPTY); ${PN}-doc, ${PN}-locale, ${PN}-src and ${PN}-staticdev are empty # and never written. Only ttf-pt-sans is installed, which is why the image entry # is one line and not two -- the opposite of ttf-ubuntu-font-family beside it, # whose `PACKAGES` assignment drops ${PN} entirely. # # THREE FAMILIES, NOT ONE. The eight faces declare `PT Sans` (PTS55F/56F/75F/76F), # `PT Sans Caption` (PTC55F/75F) and `PT Sans Narrow` (PTN57F/77F). The ticket # says "the family" in the singular; the faces say three, and the committed # control is the record of that. Only `PT Sans` has italics. # # THE BROAD `FILES:${PN} += "${datadir}"` IS THE TICKET'S HEADLINE RISK, AND THE # LAYER IT IS VISIBLE IN IS dpkg, NOT THE FILESYSTEM. A wildcard FILES entry can # only claim what THIS recipe installed into ${D} -- it cannot reach another # package's files, which is what the ticket's wording suggests -- so the real # question is whether this package ends up owning anything beyond its eight # faces. That is a statement about ownership, and every file-* case here would # look identical either way. `dpkg-owns-manifest` and `dpkg-no-foreign` compare # /var/lib/dpkg/info/ttf-pt-sans.list against the manifest in both directions, # which is the only assertion that can answer it. # # THE do_install GLOB IS NON-RECURSIVE, WHICH IS WHY THIS RECIPE ESCAPES THE # ttf-roboto DEFECT. Its body is `cd ..` then `for i in *.ttf`. ${S} is # ${WORKDIR}/ttf-pt-sans-1.1 and does not exist in the unpacked tree -- PTSans.zip # is flat -- so it is created empty by do_install's own [dirs] flag and `cd ..` # lands in ${WORKDIR}, where the zip's eight faces are. ${D} is ${WORKDIR}/image, # a DIRECTORY, so a shell glob for `*.ttf` cannot match it and cannot re-discover # an already-installed face. ttf-roboto reached the same directory with ttf.inc's # RECURSIVE `find ./ -name '*.tt[cf]'` from a scan root that contained ${D}, and # BRINTOS-1723 had to land a bbappend for it. Measured here rather than assumed: # log.do_install for this build is clean -- no `install: ... are the same file` # line, which is that defect's signature. # # ONE bbappend WAS NEEDED, AND IT IS ABOUT THE POSTINST. The recipe carries its # own pkg_postinst that runs mkfontdir and mkfontscale over ${datadir}/fonts/X11. # When this suite was written neither tool was on this image, and since the deb # packaging prepends `set -e' the stock scriptlet exited 127 at the first # mkfontdir and NEVER REACHED the fc-cache call fontcache.bbclass appends after # it -- measured as a control, exit 127 with a marker line after the loops never # printed. BRINTOS-2310 PUT BOTH TOOLS ON THE IMAGE (the mkfontscale package), so # that failure mode is gone and the append is needed for a different reason: the # loops now SUCCEED and write fonts.dir and fonts.scale into # /usr/share/fonts/X11/TTF, indexes only the core X font path reads and nothing # here does. Dying became littering. ttf-pt-sans_%.bbappend empties # pkg_postinst:${PN} either way, so fontcache's own scriptlet is the whole # postinst. # `postinst-no-mkfontdir` is the case that goes red if that append is dropped, # and it is the reason this port can satisfy the ticket's "fc-cache has left a # usable cache" clause at all. # # FOUR LAYERS, AND A RED IN AN EARLIER ONE LOCALISES A RED IN A LATER ONE: # # file-*, ttf-*, the payload arrived intact -- size, bytes, mode, type -- # x11-*, cotenant-* in a directory of its own, and the two shared font # directories were not disturbed. No font machinery at all. # dpkg-*, pkg-*, what the package DATABASE says this package owns and # postinst-* depends on, and the deferred first-boot scriptlet. # fcq-* fontconfig's independent parse of the eight files, against # a native x86-64 fontconfig 2.15.0 control. # fc-* discovery and matching THROUGH THE CACHE, which is a # different path again, and the generics this port does NOT # take. # # THIS PORT TAKES OVER NO GENERIC, AND THAT IS MEASURED RATHER THAN ASSERTED. # "PT Sans" appears nowhere in the shipped fontconfig configuration -- not in # 60-latin.conf, not in 45-latin.conf, not anywhere under /etc/fonts -- so it is # on no preference list. Confirmed by a negative-controlled A/B on the host with # the image's own /etc/fonts and its own font set: 67 faces without this package # and 75 with it, and serif, sans-serif, monospace, sans, mono, system-ui, # fantasy, cursive, emoji and math resolve to the same face in both arms. # # ONLY THE THREE CLASSIC GENERICS ARE PINNED HERE. system-ui, fantasy and cursive # have no preference list in this fontconfig at all, so they fall to whichever # face sorts first across the WHOLE image -- which moves with every neighbouring # font port and is not this port's to pin. The A/B above shows this package does # not change them; a case asserting their value would be asserting a neighbour's # state. . "$BST_LIB" S=ttf-pt-sans # THE CANARY, which asserts nothing about ttf-pt-sans. # # 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 be eaten too. # # Remove this case when linux-in-the-browser#177 is fixed. bst_ok $S/suite-canary D=$BST_DATA REF=$D/ttf-pt-sans-manifest.txt FACES=$D/ttf-pt-sans-fcfaces.txt TTFDIR=/usr/share/fonts/X11/TTF X11DIR=/usr/share/fonts/X11 COT1=/usr/share/fonts/ttf COT2=/usr/share/fonts/truetype DPKGLIST=/var/lib/dpkg/info/ttf-pt-sans.list POSTINST=/var/lib/dpkg/info/ttf-pt-sans.postinst tmp=${TMPDIR:-/tmp} W=$tmp/bst-ttf-pt-sans.$$ require gawk $S/gawk-present require sha256sum $S/sha256sum-present require find $S/find-present # fc-scan runs in the payload block, ahead of the consumer block's own check, so # its absence is guarded here. It is NOT a `require`: fontconfig-utils is a hard # Depends of this package, so an absent fc-scan is a defect in the port rather # than a legitimately absent tool, and a skip would report it green. if [ -x /usr/bin/fc-scan ]; then bst_ok $S/fc-scan-present else bst_notok $S/fc-scan-present "fontconfig-utils is a Depends of ttf-pt-sans but /usr/bin/fc-scan is absent"; fi if [ ! -f "$REF" ] || [ ! -f "$FACES" ]; then bst_notok $S/ref-present "the reference data did not ship: $REF / $FACES" exit 0 fi bst_ok $S/ref-present # ------------------------------------------------------------- payload shape # One find over this package's directory, its parent, and the two co-tenant font # directories, so every count below 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. # # NO PIPELINE, AND THAT IS NOT A STYLE CHOICE -- see the fc-scan block below. # The awk indexes every one of these lines by path, so the sort this used to # carry sorted nothing that was read in order. find "$TTFDIR" "$X11DIR" "$COT1" "$COT2" \ -maxdepth 1 -printf '%p %y %s %m %l\n' > "$W.inv" 2>/dev/null # One sha256sum over the eight payload files. Named explicitly rather than # globbed: the manifest is the list, and a glob would silently digest whatever # else had appeared in the directory and report it as an unexpected entry rather # than as the co-tenant it is. sha256sum "$TTFDIR"/PTC55F.ttf "$TTFDIR"/PTC75F.ttf \ "$TTFDIR"/PTN57F.ttf "$TTFDIR"/PTN77F.ttf \ "$TTFDIR"/PTS55F.ttf "$TTFDIR"/PTS56F.ttf \ "$TTFDIR"/PTS75F.ttf "$TTFDIR"/PTS76F.ttf > "$W.sums" 2>&1 # One fc-scan over all eight installed faces. fontconfig opens them through # FreeType, so this is a second, independent parse -- and it reads fields # FreeType's own API does not name (the PostScript name, the derived # slant/weight/spacing, the format, the charset). It reads the FILES, not the # cache, so it is independent of the fc-cache in the consumer block below. # # SCANNED FROM A TMPFS COPY, NOT FROM THE ROOTFS -- AND THAT IS THE ONLY FORM OF # THIS CALL THAT COMPLETES ON THIS IMAGE. # # fontconfig opens each face through FreeType, which maps it. On this arm a # file-backed MAP_SHARED mapping of a rootfs file is an EAGER SNAPSHOT populated # by pread64 over the cloud FUSE bridge, and for these faces that population # FAILS -- `hwjs-mmap ... file-backed mmap REFUSED (pread64 population failed) # ... errno 517 (linux-in-the-browser#72)`, observed on the 553,132- and # 584,812-byte faces, the two largest this package installs and the two largest # in any font package on this image. The refused mapping does not come back as # an error the caller handles: the process PARKS. Four runs of this suite # scanning the faces in place reached exactly three cases and were killed at the # 600 s suite bound, and a `timeout -k 5 120` around the call did NOT reclaim it, # which is what says park rather than slow. # # /tmp is a tmpfs (mode 1777, session-local), so a mapping of a copy there never # reaches the FUSE bridge and cannot hit the refusal. `%{file|basename}` is what # the committed control is keyed on, so scanning the copy asserts exactly the # same rows. The bytes are proved identical by the sha256sum above, which uses # read() and not mmap -- so this does not weaken the payload assertion, it moves # only the PARSE off the bridge. 99-ttf-gentium stages its freetype probe into # /tmp for the same class of reason. # # BRINTOS-WORKAROUND: linux-in-the-browser#72 remove -- scan a tmpfs copy rather # than the installed file; goes when a file-backed mmap whose pread64 population # fails returns an error to the caller instead of parking it. _cpok=1 mkdir -p "$W.d" 2>/dev/null || _cpok=0 for _b in PTC55F PTC75F PTN57F PTN77F PTS55F PTS56F PTS75F PTS76F; do cp "$TTFDIR/$_b.ttf" "$W.d/$_b.ttf" 2>/dev/null || _cpok=0 done if [ "$_cpok" -eq 1 ]; then bst_ok $S/fcq-stage else bst_notok $S/fcq-stage "could not stage the eight faces into $W.d for the fc-scan parse"; fi LC_ALL=C fc-scan --format '%{file|basename}|%{family}|%{style}|%{slant}|%{weight}|%{spacing}|%{postscriptname}|%{fontformat}|%{scalable}|%{outline}|%{charset}\n' \ "$W.d"/PTC55F.ttf "$W.d"/PTC75F.ttf \ "$W.d"/PTN57F.ttf "$W.d"/PTN77F.ttf \ "$W.d"/PTS55F.ttf "$W.d"/PTS56F.ttf \ "$W.d"/PTS75F.ttf "$W.d"/PTS76F.ttf > "$W.scan" 2>/dev/null # dpkg's own record of what this package owns. Copied to tmpfs rather than read # in place for the reason brintos/linux#73 gives; an absent file leaves an empty # copy, which `dpkg-list-read` reports rather than passing over. cat "$DPKGLIST" > "$W.dpkg" 2>/dev/null || : > "$W.dpkg" LC_ALL=C gawk -v REF="$REF" -v SUMS="$W.sums" -v INV="$W.inv" \ -v FACES="$FACES" -v SCAN="$W.scan" -v DPKG="$W.dpkg" \ -f "$D/ttf-pt-sans-verify.awk" "$REF" "$W.sums" "$W.inv" "$FACES" "$W.scan" "$W.dpkg" # ---------------------------------------------------- the packaging on target # One sed pulls the stanzas this suite asks about; the loop is shell builtins. # ttf-pt-sans-dbg and ttf-pt-sans-dev are built as EMPTY packages (ALLOW_EMPTY), # and the image installs neither -- so their absence from the database is a # statement about the image entry, which names one package and not three. sed -n '/^Package: ttf-pt-sans$/,/^$/p; /^Package: ttf-pt-sans-doc$/,/^$/p; /^Package: ttf-pt-sans-dbg$/,/^$/p; /^Package: ttf-pt-sans-dev$/,/^$/p' \ /var/lib/dpkg/status > "$W.st" 2>/dev/null _pkg=""; _main=0; _doc=0; _dbg=0; _dev=0; _arch=0; _dep=0 while IFS= read -r l; do case "$l" in "Package: ttf-pt-sans") _pkg=main; _main=1 ;; "Package: ttf-pt-sans-doc") _pkg=doc; _doc=1 ;; "Package: ttf-pt-sans-dbg") _pkg=dbg; _dbg=1 ;; "Package: ttf-pt-sans-dev") _pkg=dev; _dev=1 ;; "Architecture: all") [ "$_pkg" = main ] && _arch=1 ;; "Depends: "*) case "$l" in *fontconfig-utils*) [ "$_pkg" = main ] && _dep=1 ;; esac ;; esac done < "$W.st" if [ "$_main" -eq 1 ]; then bst_ok $S/pkg-known else bst_notok $S/pkg-known "dpkg does not know the package ttf-pt-sans"; fi # `allarch` reached the package metadata, which is what makes the byte-identity # reference in the manifest a statement about this build rather than a # coincidence. if [ "$_arch" -eq 1 ]; then bst_ok $S/pkg-arch-all else bst_notok $S/pkg-arch-all "ttf-pt-sans is not Architecture: all"; fi # THE fontcache CLASS'S RDEPENDS, READ BACK OFF THE TARGET. The recipe declares # no runtime dependency at all and `allarch` sets INHIBIT_DEFAULT_DEPS -- # fontcache.bbclass appends ${MLPREFIX}fontconfig-utils to each FONT_PACKAGES # entry -- so this is the case that says the class did its half and that the # dependency resolved against a package this image already carried. if [ "$_dep" -eq 1 ]; then bst_ok $S/pkg-depends-fontconfig else bst_notok $S/pkg-depends-fontconfig "ttf-pt-sans does not Depend on fontconfig-utils"; fi # NO -doc PACKAGE EXISTS AND NONE IS INSTALLED. The zip carries five text/PDF # members including two licence texts, and none of them is packaged: do_install's # loop is `for i in *.ttf`. "the -doc line was forgotten" and "there is no -doc # package to forget" look identical from the file layer alone, so this names it. if [ "$_doc" -eq 0 ]; then bst_ok $S/pkg-no-doc-package else bst_notok $S/pkg-no-doc-package "dpkg knows a ttf-pt-sans-doc package"; fi if [ "$_dbg" -eq 0 ] && [ "$_dev" -eq 0 ]; then bst_ok $S/pkg-no-empty-subpackages else bst_notok $S/pkg-no-empty-subpackages "the image installed an empty subpackage: dbg=$_dbg dev=$_dev"; fi # ------------------------------------------------- the deferred fontcache hook # fontcache.bbclass registers an update_font_cache intercept that runs fc-cache # under qemu-user. There is no wasm32 qemu-user, so it is deferred to # run-postinsts at first boot, which /etc/inittab does run (BRINTOS-53). Whether # it HAS run depends on the pid 1 the harness booted -- the local runner goes # straight to a shell -- so asserting the configured state would report the # runner's choice as a package red. What is asserted instead is boot-mode # independent: the scriptlet is on the image, it calls fc-cache, it does NOT call # mkfontdir/mkfontscale, and fc-cache is present. if [ -f "$POSTINST" ]; then bst_ok $S/postinst-present else bst_notok $S/postinst-present "$POSTINST is absent -- the fontcache postinst did not reach the image"; fi check_out $S/postinst-runs-fc-cache "fc-cache" cat "$POSTINST" # THE bbappend'S OWN GUARD. Without ttf-pt-sans_%.bbappend the postinst carries # the recipe's mkfontdir/mkfontscale loops. A `check_out` for fc-cache passes # either way, because the text is still in the file; only its ABSENCE of # mkfontdir says the scriptlet can reach it. # # WHY THE CASE SURVIVES A CHANGE OF PREMISE. It was written for an image with no # X11 font utility, where the loops exited 127 at the first `mkfontdir: not # found' and `set -e' took the scriptlet down before fc-cache. BRINTOS-2310 put # the `mkfontscale' package on the image, so that failure mode is gone -- and the # guard is still right, for the reason ttf-pt-sans_%.bbappend gives in its own # words: the loops would now SUCCEED and write fonts.dir and fonts.scale into # /usr/share/fonts/X11/TTF, indexes only the core X font path reads and nothing # on this image does. The scriptlet went from dying to producing litter. Either # way it is not what should run, so the assertion below is unchanged. if grep -q 'mkfontdir\|mkfontscale' "$POSTINST" 2>/dev/null; then bst_notok $S/postinst-no-mkfontdir "$POSTINST calls mkfontdir/mkfontscale; both are on this image since BRINTOS-2310, so the loops now SUCCEED and write fonts.dir/fonts.scale into /usr/share/fonts/X11/TTF -- indexes nothing here reads. The ttf-pt-sans bbappend is not in effect" else bst_ok $S/postinst-no-mkfontdir fi # ...and BOTH tools ARE on the image, which is this ticket's doing and is asserted # rather than assumed. BRINTOS-2310 adds `mkfontscale' to # packagegroup-brintos-extra.bb; the package ships /usr/bin/mkfontscale and the # 65-byte /usr/bin/mkfontdir wrapper (`exec mkfontscale -b -s -l "$@"'), both read # off the staged rootfs and owned by mkfontscale.list. # # This case used to assert the opposite. It is kept, inverted, rather than deleted: # the premise moved, the tripwire did not. If a later image drops the package the # red lands here and points at the paragraph above, which is where the reasoning # for the bbappend now lives. if command -v mkfontdir >/dev/null 2>&1 && command -v mkfontscale >/dev/null 2>&1; then bst_ok $S/x11-font-utils-present else bst_notok $S/x11-font-utils-present "mkfontdir/mkfontscale are NOT on this image -- BRINTOS-2310 put the mkfontscale package in packagegroup-brintos-extra; something dropped it" fi # ...and the tool the deferred branch needs is present, so that run cannot fail # for want of it. This is the ticket's stated risk, and it is a shell builtin. if [ -x /usr/bin/fc-cache ]; then bst_ok $S/fc-cache-present else bst_notok $S/fc-cache-present "fontconfig-utils is a Depends of ttf-pt-sans but /usr/bin/fc-cache is absent"; fi # --------------------------------------------------------- the consumer block # # THIS SUITE CALLS `fc-cache`, NOT `fc-cache -f`, AND THAT ONE TOKEN IS THE # DIFFERENCE BETWEEN A SUITE THAT FINISHES AND ONE THAT DOES NOT. Every other # font suite on this image forced a rebuild until this ticket; four bounded the # call against linux-in-the-browser#165 and four did not, and on THIS image all # four that were run parked at it -- see the measurement below and the design # doc's A/B. # # WHY IT PARKS HERE AND DID NOT BEFORE. `fc-cache -f` rebuilds every directory # whether or not its cache is valid, which means mapping every face on the # image. A file-backed MAP_SHARED mapping of a rootfs file is an eager pread64 # snapshot over the cloud FUSE bridge, and above roughly 578 kB it is REFUSED # and the caller PARKS (#165, bracketed by BRINTOS-1450). Before this port the # image's largest face was Ubuntu-L.ttf at 415,552 bytes -- under the bracket. # This package installs four faces above that, the largest 584,812, so it is the # port that puts the image over the line. # # WITHOUT `-f`, fc-cache rebuilds only what is stale, and nothing is: # /var/cache/fontconfig ships POPULATED, seven cache files built at image time. # MEASURED on this image, 2026-08-29: `fc-cache` returns 0 in 3 s, twice in a # row, and `fc-list` then enumerates all 75 faces -- while `timeout -k 5 150 # fc-cache -f` in the same boot never returned, and the bound did not reclaim it, # because a parked mapping survives SIGKILL. # # BRINTOS-WORKAROUND: linux-in-the-browser#165 revisit -- call fc-cache without # -f so only a stale cache is rebuilt; the -f goes back in when the mmap # population path tolerates a parking read. _nc=0 for _f in /var/cache/fontconfig/*; do [ -e "$_f" ] && _nc=$((_nc+1)); done if [ "$_nc" -ge 1 ]; then bst_ok $S/fc-cache-shipped else bst_notok $S/fc-cache-shipped "/var/cache/fontconfig is empty -- no cache was built at image time, so the fc-cache below would rebuild every directory and park"; fi # BST-TIMEOUT-OK: fc-cache walks the font dirs and exits; -k 5 90 is belt-and-braces. timeout -k 5 90 fc-cache > "$W.cache" 2>&1 _rc=$? if [ "$_rc" -eq 0 ]; then bst_ok $S/fc-cache-rc elif [ "$_rc" -eq 124 ] || [ "$_rc" -eq 137 ]; then bst_notok $S/fc-cache-rc "fc-cache did not return within 90s -- linux-in-the-browser#165 (mmap population parked); a cache went stale, so this call rebuilt a directory" 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 # THE FACES ARE DISCOVERABLE, not merely present on disk. A cache that serialised # wrongly, or a FreeType that refused the outlines, shows up here while every # file-* case above stays green -- which is the split that says where to look. for _pair in "PTC55F.ttf:PT Sans Caption" "PTC75F.ttf:PT Sans Caption" \ "PTN57F.ttf:PT Sans Narrow" "PTN77F.ttf:PT Sans Narrow" \ "PTS55F.ttf:PT Sans" "PTS56F.ttf:PT Sans" \ "PTS75F.ttf:PT Sans" "PTS76F.ttf:PT Sans"; do _bn=${_pair%%:*}; _wantfam=${_pair#*:} _seen=0; _fam="" while IFS= read -r l; do case "$l" in "$TTFDIR/$_bn":*) ;; *) continue ;; esac _seen=$((_seen+1)) _fam=${l#*: } done < "$W.list" if [ "$_seen" -eq 1 ] && [ "$_fam" = "$_wantfam" ]; then bst_ok "$S/fc-list-$_bn" else bst_notok "$S/fc-list-$_bn" "fc-list reports $_seen entries for $TTFDIR/$_bn family '$_fam', want 1 of '$_wantfam'" fi done # ...AND EACH FAMILY RESOLVES BACK TO OUR REGULAR FACE. fc-match never fails -- # it always returns some face -- so this is real only because 67 other faces are # installed alongside: measured on the host A/B, all three of these family names # resolve to Liberation Mono when this package is absent. This is the assertion # that the font is USABLE and not merely present on disk. for _pair in "PT Sans:PTS55F.ttf" "PT Sans Caption:PTC55F.ttf" "PT Sans Narrow:PTN57F.ttf"; do _fam=${_pair%%:*}; _wantf=${_pair#*:} _out=$(fc-match --format '%{file} %{family}\n' "$_fam" 2>&1) case "$_out" in "$TTFDIR/$_wantf $_fam") bst_ok "$S/fc-match-$_wantf" ;; *) bst_notok "$S/fc-match-$_wantf" "fc-match '$_fam' => '$(_bst_1line "$_out")', want '$TTFDIR/$_wantf $_fam'" ;; esac done # NOTHING IS LISTED UNDER A FAMILY THIS RELEASE DOES NOT PROVIDE. # # THE TICKET'S CLAUSE AS WRITTEN CANNOT BE ASSERTED, and saying so is the point. # It asks that `fc-match` for a family this package does not provide "not # resolve". fc-match always returns a best match; it has no way to express # non-resolution, and on this image all five names below answer `Liberation Mono` # by fallback -- so a case built on the clause as written would assert nothing # while looking strict. What the clause is reaching for is that a mis-scoped # fontconfig entry must not make these names resolvable HERE, and `fc-list # :family=` reports that directly. Same narrowing BRINTOS-1723 and BRINTOS-1724 # made, for the same reason. # # The five are real ParaType family names from the same foundry -- PT Serif, PT # Mono and PT Root UI are separate releases this recipe does not ship -- plus two # style-qualified names that are a face of a family here, not a family. for _fam in "PT Serif" "PT Mono" "PT Root UI" "PT Sans Bold" "PT Sans Narrow Bold"; do fc-list ":family=$_fam" file > "$W.absent" 2>/dev/null _n=0; while IFS= read -r l; do [ -n "$l" ] && _n=$((_n+1)); done < "$W.absent" _id=$(printf '%s' "$_fam" | tr ' ' '-') if [ "$_n" -eq 0 ]; then bst_ok "$S/fc-list-absent-$_id" else bst_notok "$S/fc-list-absent-$_id" "fc-list :family=$_fam reports $_n entries; this release ships no such family"; fi done # THE GENERICS THIS PORT DOES **NOT** TAKE OVER, ASSERTED FROM THIS SIDE. # "PT Sans" is on no preference list in the shipped fontconfig configuration -- # `grep -ril "pt sans" /etc/fonts` returns nothing -- so the three classic # generics keep their incumbents: Liberation Serif and Liberation Sans reach # theirs through 30-metric-aliases.conf, and Source Code Pro takes monospace # through its own 44-source-code-pro-fonts-fontconfig.conf. This is NOT a # restatement of the fc-match-PT* cases: those would stay green if installing # these families had ALSO displaced a generic, which is precisely what installing # ttf-inconsolata once did to monospace. The four neighbouring font suites assert # the same facts from the other side, so a disagreement is visible rather than # silent. # AMENDED FOR BRINTOS-1729 (ttf-tlwg), WHICH TAKES sans-serif AND serif # IMAGE-WIDE. ttf-tlwg ships ten fragments into /etc/fonts/conf.d # at 64; PREPENDS ahead of the generic while 30-liberation-aliases.conf's # only APPENDS behind it, so Kinnari takes `serif` and Waree takes # `sans-serif` for every suite on this image at once. It is CONFIGURATION-driven, # so it does not depend on how large the font set is. monospace is unaffected -- # source-code-pro-fonts' own loads at 44, ahead of these. THE CASE IS # AMENDED, NOT DELETED: what it asserts is that THIS port does not take a generic, # which is still true, and only the value it is compared against moved. for _pair in "serif:Kinnari" "sans-serif:Waree" "monospace:Source Code Pro"; do _gen=${_pair%%:*}; _want=${_pair#*:} _out=$(fc-match --format '%{family}\n' "$_gen" 2>&1) if [ "$_out" = "$_want" ]; then bst_ok "$S/fc-match-$_gen-unchanged" else bst_notok "$S/fc-match-$_gen-unchanged" "fc-match $_gen => '$(_bst_1line "$_out")', want '$_want' -- this port must not take a generic"; fi done rm -rf "$W.d" 2>/dev/null rm -f "$W.inv" "$W.sums" "$W.scan" "$W.st" "$W.dpkg" "$W.cache" "$W.list" "$W.absent" 2>/dev/null