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>
16 lines
756 B
JavaScript
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);
|
|
};
|