Files
rea/scripts/lib/verify-package-listing.mjs
T
5b08d04302 fix(package): parse tar listings without platform line endings (#4315)
Windows ships two tar implementations. `C:\Windows\System32\tar.exe` (bsdtar)
terminates every listed member with CRLF, so `verify-package-pack.mjs`
splitting the listing on a bare "\n" left a trailing "\r" on each non-final
member. `verifyPackedBridge` compares member identities exactly, so it reported
`package omitted package/bridge/hopper_bridge.py` although the tarball ships
that member (#4128).

`parseTarListing` normalizes line endings once, at the listing owner, and
preserves every member string beyond its line ending. `verifyPackagePack` is
the only tar listing producer in the package verifiers, so its consumers now
compare bare member names; the prefix checks in the same file keep their
behavior because they never matched a line ending.

Covered by `tests/conformance/package/packedTarListing.test.ts`: CRLF and LF
listings both yield exact bridge identities, the trailing line ending no longer
produces an empty member, member strings keep embedded spaces, and a regression
guard pins the previous parse's failure.

Real Windows 11 evidence (`package/bridge/hopper_bridge.py` in the listing):

| tar                                | listing | split("\n") | parseTarListing |
| ---------------------------------- | ------- | ----------- | --------------- |
| Git for Windows GNU tar            | LF      | true        | true            |
| C:\Windows\System32\tar.exe        | CRLF    | false       | true            |

Fixes #4128

Co-authored-by: Chow Kim <catch@126.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 00:09:59 +08:00

16 lines
756 B
JavaScript

/**
* Parse a `tar -tf` listing into its member names.
*
* Windows `tar` terminates each listed member with CRLF, so splitting on a
* bare "\n" leaves a trailing "\r" on every non-final member. Consumers
* compare member identities exactly (`packedFiles.includes(path)`), so those
* carriers make members that ship in the package look omitted. One listing
* uses one separator: a bare LF identifies LF output, whose CR bytes then
* belong to filenames. Normalize here, once, at the listing owner, and
* preserve every member string beyond its line ending.
*/
export const parseTarListing = (stdout) => {
const lineEnding = /(^|[^\r])\n/u.test(stdout) ? "\n" : "\r\n";
return stdout.split(lineEnding).filter((member) => member.length > 0);
};