@@ -15,12 +15,13 @@ const MIN_REQUIRED_BSD_TAR_VERSION = "3.4.3";
1515const MIN_REQUIRED_GNU_TAR_VERSION = "1.31";
1616
1717export type TarVersion = {
18+ name: string;
1819 type: "gnu" | "bsd";
1920 version: string;
2021};
2122
22- async function getTarVersion(): Promise<TarVersion> {
23- const tar = await io.which("tar" , true);
23+ async function getTarVersion(programName: string ): Promise<TarVersion> {
24+ const tar = await io.which(programName , true);
2425 let stdout = "";
2526 const exitCode = await new ToolRunner(tar, ["--version"], {
2627 listeners: {
@@ -30,28 +31,43 @@ async function getTarVersion(): Promise<TarVersion> {
3031 },
3132 }).exec();
3233 if (exitCode !== 0) {
33- throw new Error(" Failed to call tar --version" );
34+ throw new Error(` Failed to call ${programName} --version` );
3435 }
3536 // Return whether this is GNU tar or BSD tar, and the version number
3637 if (stdout.includes("GNU tar")) {
3738 const match = stdout.match(/tar \(GNU tar\) ([0-9.]+)/);
3839 if (!match || !match[1]) {
39- throw new Error(" Failed to parse output of tar --version." );
40+ throw new Error(` Failed to parse output of ${programName} --version.` );
4041 }
4142
42- return { type: "gnu", version: match[1] };
43+ return { name: programName, type: "gnu", version: match[1] };
4344 } else if (stdout.includes("bsdtar")) {
4445 const match = stdout.match(/bsdtar ([0-9.]+)/);
4546 if (!match || !match[1]) {
46- throw new Error(" Failed to parse output of tar --version." );
47+ throw new Error(` Failed to parse output of ${programName} --version.` );
4748 }
4849
49- return { type: "bsd", version: match[1] };
50+ return { name: programName, type: "bsd", version: match[1] };
5051 } else {
5152 throw new Error("Unknown tar version");
5253 }
5354}
5455
56+ async function pickTarCommand(): Promise<TarVersion> {
57+ // bsdtar 3.5.3 on the macos-14 (arm) action runner image is prone to crash with the following
58+ // error messages when extracting zstd archives:
59+ //
60+ // tar: Child process exited with status 1
61+ // tar: Error exit delayed from previous errors.
62+ //
63+ // To avoid this problem, prefer GNU tar under the name "gtar" if it is available.
64+ try {
65+ return await getTarVersion("gtar");
66+ } catch {
67+ return await getTarVersion("tar");
68+ }
69+ }
70+
5571export interface ZstdAvailability {
5672 available: boolean;
5773 foundZstdBinary: boolean;
@@ -63,7 +79,7 @@ export async function isZstdAvailable(
6379): Promise<ZstdAvailability> {
6480 const foundZstdBinary = await isBinaryAccessible("zstd", logger);
6581 try {
66- const tarVersion = await getTarVersion ();
82+ const tarVersion = await pickTarCommand ();
6783 const { type, version } = tarVersion;
6884 logger.info(`Found ${type} tar version ${version}.`);
6985 switch (type) {
@@ -162,10 +178,10 @@ export async function extractTarZst(
162178
163179 args.push("-f", tar instanceof stream.Readable ? "-" : tar, "-C", dest);
164180
165- process.stdout.write(`[command]tar ${args.join(" ")}\n`);
181+ process.stdout.write(`[command]${tarVersion.name} ${args.join(" ")}\n`);
166182
167183 await new Promise<void>((resolve, reject) => {
168- const tarProcess = spawn("tar" , args, { stdio: "pipe" });
184+ const tarProcess = spawn(tarVersion.name , args, { stdio: "pipe" });
169185
170186 let stdout = "";
171187 tarProcess.stdout?.on("data", (data: Buffer) => {
@@ -196,7 +212,7 @@ export async function extractTarZst(
196212 if (code !== 0) {
197213 reject(
198214 new CommandInvocationError(
199- "tar" ,
215+ tarVersion.name ,
200216 args,
201217 code ?? undefined,
202218 stdout,
0 commit comments