Revert "Prefer gtar if available"
This commit is contained in:
parent
acadfedea5
commit
65a3aa1fbc
4 changed files with 24 additions and 55 deletions
|
|
@ -4,7 +4,7 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
|
||||||
|
|
||||||
## [UNRELEASED]
|
## [UNRELEASED]
|
||||||
|
|
||||||
- Update the action to prefer `gtar` over `tar` to make zstd archive extraction more robust. [2767](https://github.com/github/codeql-action/pull/2767)
|
No user facing changes.
|
||||||
|
|
||||||
## 3.28.9 - 07 Feb 2025
|
## 3.28.9 - 07 Feb 2025
|
||||||
|
|
||||||
|
|
|
||||||
37
lib/tar.js
generated
37
lib/tar.js
generated
|
|
@ -48,8 +48,8 @@ const actions_util_1 = require("./actions-util");
|
||||||
const util_1 = require("./util");
|
const util_1 = require("./util");
|
||||||
const MIN_REQUIRED_BSD_TAR_VERSION = "3.4.3";
|
const MIN_REQUIRED_BSD_TAR_VERSION = "3.4.3";
|
||||||
const MIN_REQUIRED_GNU_TAR_VERSION = "1.31";
|
const MIN_REQUIRED_GNU_TAR_VERSION = "1.31";
|
||||||
async function getTarVersion(programName) {
|
async function getTarVersion() {
|
||||||
const tar = await io.which(programName, true);
|
const tar = await io.which("tar", true);
|
||||||
let stdout = "";
|
let stdout = "";
|
||||||
const exitCode = await new toolrunner_1.ToolRunner(tar, ["--version"], {
|
const exitCode = await new toolrunner_1.ToolRunner(tar, ["--version"], {
|
||||||
listeners: {
|
listeners: {
|
||||||
|
|
@ -59,46 +59,31 @@ async function getTarVersion(programName) {
|
||||||
},
|
},
|
||||||
}).exec();
|
}).exec();
|
||||||
if (exitCode !== 0) {
|
if (exitCode !== 0) {
|
||||||
throw new Error(`Failed to call ${programName} --version`);
|
throw new Error("Failed to call tar --version");
|
||||||
}
|
}
|
||||||
// Return whether this is GNU tar or BSD tar, and the version number
|
// Return whether this is GNU tar or BSD tar, and the version number
|
||||||
if (stdout.includes("GNU tar")) {
|
if (stdout.includes("GNU tar")) {
|
||||||
const match = stdout.match(/tar \(GNU tar\) ([0-9.]+)/);
|
const match = stdout.match(/tar \(GNU tar\) ([0-9.]+)/);
|
||||||
if (!match || !match[1]) {
|
if (!match || !match[1]) {
|
||||||
throw new Error(`Failed to parse output of ${programName} --version.`);
|
throw new Error("Failed to parse output of tar --version.");
|
||||||
}
|
}
|
||||||
return { name: programName, type: "gnu", version: match[1] };
|
return { type: "gnu", version: match[1] };
|
||||||
}
|
}
|
||||||
else if (stdout.includes("bsdtar")) {
|
else if (stdout.includes("bsdtar")) {
|
||||||
const match = stdout.match(/bsdtar ([0-9.]+)/);
|
const match = stdout.match(/bsdtar ([0-9.]+)/);
|
||||||
if (!match || !match[1]) {
|
if (!match || !match[1]) {
|
||||||
throw new Error(`Failed to parse output of ${programName} --version.`);
|
throw new Error("Failed to parse output of tar --version.");
|
||||||
}
|
}
|
||||||
return { name: programName, type: "bsd", version: match[1] };
|
return { type: "bsd", version: match[1] };
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new Error("Unknown tar version");
|
throw new Error("Unknown tar version");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function pickTarCommand() {
|
|
||||||
// bsdtar 3.5.3 on the macos-14 (arm) action runner image is prone to crash with the following
|
|
||||||
// error messages when extracting zstd archives:
|
|
||||||
//
|
|
||||||
// tar: Child process exited with status 1
|
|
||||||
// tar: Error exit delayed from previous errors.
|
|
||||||
//
|
|
||||||
// To avoid this problem, prefer GNU tar under the name "gtar" if it is available.
|
|
||||||
try {
|
|
||||||
return await getTarVersion("gtar");
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
return await getTarVersion("tar");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function isZstdAvailable(logger) {
|
async function isZstdAvailable(logger) {
|
||||||
const foundZstdBinary = await (0, util_1.isBinaryAccessible)("zstd", logger);
|
const foundZstdBinary = await (0, util_1.isBinaryAccessible)("zstd", logger);
|
||||||
try {
|
try {
|
||||||
const tarVersion = await pickTarCommand();
|
const tarVersion = await getTarVersion();
|
||||||
const { type, version } = tarVersion;
|
const { type, version } = tarVersion;
|
||||||
logger.info(`Found ${type} tar version ${version}.`);
|
logger.info(`Found ${type} tar version ${version}.`);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
@ -165,9 +150,9 @@ async function extractTarZst(tar, dest, tarVersion, logger) {
|
||||||
args.push("--overwrite");
|
args.push("--overwrite");
|
||||||
}
|
}
|
||||||
args.push("-f", tar instanceof stream.Readable ? "-" : tar, "-C", dest);
|
args.push("-f", tar instanceof stream.Readable ? "-" : tar, "-C", dest);
|
||||||
process.stdout.write(`[command]${tarVersion.name} ${args.join(" ")}\n`);
|
process.stdout.write(`[command]tar ${args.join(" ")}\n`);
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
const tarProcess = (0, child_process_1.spawn)(tarVersion.name, args, { stdio: "pipe" });
|
const tarProcess = (0, child_process_1.spawn)("tar", args, { stdio: "pipe" });
|
||||||
let stdout = "";
|
let stdout = "";
|
||||||
tarProcess.stdout?.on("data", (data) => {
|
tarProcess.stdout?.on("data", (data) => {
|
||||||
stdout += data.toString();
|
stdout += data.toString();
|
||||||
|
|
@ -189,7 +174,7 @@ async function extractTarZst(tar, dest, tarVersion, logger) {
|
||||||
}
|
}
|
||||||
tarProcess.on("exit", (code) => {
|
tarProcess.on("exit", (code) => {
|
||||||
if (code !== 0) {
|
if (code !== 0) {
|
||||||
reject(new actions_util_1.CommandInvocationError(tarVersion.name, args, code ?? undefined, stdout, stderr));
|
reject(new actions_util_1.CommandInvocationError("tar", args, code ?? undefined, stdout, stderr));
|
||||||
}
|
}
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
38
src/tar.ts
38
src/tar.ts
|
|
@ -15,13 +15,12 @@ const MIN_REQUIRED_BSD_TAR_VERSION = "3.4.3";
|
||||||
const MIN_REQUIRED_GNU_TAR_VERSION = "1.31";
|
const MIN_REQUIRED_GNU_TAR_VERSION = "1.31";
|
||||||
|
|
||||||
export type TarVersion = {
|
export type TarVersion = {
|
||||||
name: string;
|
|
||||||
type: "gnu" | "bsd";
|
type: "gnu" | "bsd";
|
||||||
version: string;
|
version: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
async function getTarVersion(programName: string): Promise<TarVersion> {
|
async function getTarVersion(): Promise<TarVersion> {
|
||||||
const tar = await io.which(programName, true);
|
const tar = await io.which("tar", true);
|
||||||
let stdout = "";
|
let stdout = "";
|
||||||
const exitCode = await new ToolRunner(tar, ["--version"], {
|
const exitCode = await new ToolRunner(tar, ["--version"], {
|
||||||
listeners: {
|
listeners: {
|
||||||
|
|
@ -31,43 +30,28 @@ async function getTarVersion(programName: string): Promise<TarVersion> {
|
||||||
},
|
},
|
||||||
}).exec();
|
}).exec();
|
||||||
if (exitCode !== 0) {
|
if (exitCode !== 0) {
|
||||||
throw new Error(`Failed to call ${programName} --version`);
|
throw new Error("Failed to call tar --version");
|
||||||
}
|
}
|
||||||
// Return whether this is GNU tar or BSD tar, and the version number
|
// Return whether this is GNU tar or BSD tar, and the version number
|
||||||
if (stdout.includes("GNU tar")) {
|
if (stdout.includes("GNU tar")) {
|
||||||
const match = stdout.match(/tar \(GNU tar\) ([0-9.]+)/);
|
const match = stdout.match(/tar \(GNU tar\) ([0-9.]+)/);
|
||||||
if (!match || !match[1]) {
|
if (!match || !match[1]) {
|
||||||
throw new Error(`Failed to parse output of ${programName} --version.`);
|
throw new Error("Failed to parse output of tar --version.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return { name: programName, type: "gnu", version: match[1] };
|
return { type: "gnu", version: match[1] };
|
||||||
} else if (stdout.includes("bsdtar")) {
|
} else if (stdout.includes("bsdtar")) {
|
||||||
const match = stdout.match(/bsdtar ([0-9.]+)/);
|
const match = stdout.match(/bsdtar ([0-9.]+)/);
|
||||||
if (!match || !match[1]) {
|
if (!match || !match[1]) {
|
||||||
throw new Error(`Failed to parse output of ${programName} --version.`);
|
throw new Error("Failed to parse output of tar --version.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return { name: programName, type: "bsd", version: match[1] };
|
return { type: "bsd", version: match[1] };
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Unknown tar version");
|
throw new Error("Unknown tar version");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function pickTarCommand(): Promise<TarVersion> {
|
|
||||||
// bsdtar 3.5.3 on the macos-14 (arm) action runner image is prone to crash with the following
|
|
||||||
// error messages when extracting zstd archives:
|
|
||||||
//
|
|
||||||
// tar: Child process exited with status 1
|
|
||||||
// tar: Error exit delayed from previous errors.
|
|
||||||
//
|
|
||||||
// To avoid this problem, prefer GNU tar under the name "gtar" if it is available.
|
|
||||||
try {
|
|
||||||
return await getTarVersion("gtar");
|
|
||||||
} catch {
|
|
||||||
return await getTarVersion("tar");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ZstdAvailability {
|
export interface ZstdAvailability {
|
||||||
available: boolean;
|
available: boolean;
|
||||||
foundZstdBinary: boolean;
|
foundZstdBinary: boolean;
|
||||||
|
|
@ -79,7 +63,7 @@ export async function isZstdAvailable(
|
||||||
): Promise<ZstdAvailability> {
|
): Promise<ZstdAvailability> {
|
||||||
const foundZstdBinary = await isBinaryAccessible("zstd", logger);
|
const foundZstdBinary = await isBinaryAccessible("zstd", logger);
|
||||||
try {
|
try {
|
||||||
const tarVersion = await pickTarCommand();
|
const tarVersion = await getTarVersion();
|
||||||
const { type, version } = tarVersion;
|
const { type, version } = tarVersion;
|
||||||
logger.info(`Found ${type} tar version ${version}.`);
|
logger.info(`Found ${type} tar version ${version}.`);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
@ -178,10 +162,10 @@ export async function extractTarZst(
|
||||||
|
|
||||||
args.push("-f", tar instanceof stream.Readable ? "-" : tar, "-C", dest);
|
args.push("-f", tar instanceof stream.Readable ? "-" : tar, "-C", dest);
|
||||||
|
|
||||||
process.stdout.write(`[command]${tarVersion.name} ${args.join(" ")}\n`);
|
process.stdout.write(`[command]tar ${args.join(" ")}\n`);
|
||||||
|
|
||||||
await new Promise<void>((resolve, reject) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
const tarProcess = spawn(tarVersion.name, args, { stdio: "pipe" });
|
const tarProcess = spawn("tar", args, { stdio: "pipe" });
|
||||||
|
|
||||||
let stdout = "";
|
let stdout = "";
|
||||||
tarProcess.stdout?.on("data", (data: Buffer) => {
|
tarProcess.stdout?.on("data", (data: Buffer) => {
|
||||||
|
|
@ -212,7 +196,7 @@ export async function extractTarZst(
|
||||||
if (code !== 0) {
|
if (code !== 0) {
|
||||||
reject(
|
reject(
|
||||||
new CommandInvocationError(
|
new CommandInvocationError(
|
||||||
tarVersion.name,
|
"tar",
|
||||||
args,
|
args,
|
||||||
code ?? undefined,
|
code ?? undefined,
|
||||||
stdout,
|
stdout,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue