Skip to content

Commit

Permalink
Only try zstd for specified version ranges of tar
Browse files Browse the repository at this point in the history
  • Loading branch information
Henry Mercer committed Aug 29, 2024
1 parent cf64c3e commit ffa1b05
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 48 deletions.
19 changes: 2 additions & 17 deletions lib/setup-codeql.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/setup-codeql.js.map

Large diffs are not rendered by default.

102 changes: 102 additions & 0 deletions lib/tar.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions lib/tar.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 4 additions & 30 deletions src/setup-codeql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import * as api from "./api-client";
import * as defaults from "./defaults.json";
import { CodeQLDefaultVersionInfo } from "./feature-flags";
import { Logger } from "./logging";
import * as tar from "./tar";
import * as util from "./util";
import { isGoodVersion } from "./util";

Expand Down Expand Up @@ -461,10 +462,8 @@ export async function tryGetFallbackToolcacheVersion(
return fallbackVersion;
}

type CompressionMethod = "gzip" | "zstd";

export interface ToolsDownloadStatusReport {
compressionMethod: CompressionMethod;
compressionMethod: tar.CompressionMethod;
downloadDurationMs: number;
extractionDurationMs: number;
}
Expand Down Expand Up @@ -529,9 +528,8 @@ export const downloadCodeQL = async function (

logger.debug("Extracting CodeQL bundle.");
const extractionStart = performance.now();
const { extractedBundlePath, compressionMethod } = await extractBundle(
archivedBundlePath,
);
const { compressionMethod, outputPath: extractedBundlePath } =
await tar.extract(archivedBundlePath);
const extractionDurationMs = Math.round(performance.now() - extractionStart);
logger.debug(
`Finished extracting CodeQL bundle to ${extractedBundlePath} (${extractionDurationMs} ms).`,
Expand Down Expand Up @@ -706,27 +704,3 @@ async function cleanUpGlob(glob: string, name: string, logger: Logger) {
logger.warning(`Failed to clean up ${name}: ${e}.`);
}
}

async function extractBundle(archivedBundlePath: string): Promise<{
compressionMethod: CompressionMethod;
extractedBundlePath: string;
}> {
if (archivedBundlePath.endsWith(".tar.gz")) {
return {
compressionMethod: "gzip",
// While we could also ask tar to autodetect the compression method,
// we defensively keep the gzip call identical as requesting a gzipped
// bundle will soon be a fallback option.
extractedBundlePath: await toolcache.extractTar(archivedBundlePath),
};
}
return {
compressionMethod: "zstd",
// tar will autodetect the compression method
extractedBundlePath: await toolcache.extractTar(
archivedBundlePath,
undefined,
"x",
),
};
}
91 changes: 91 additions & 0 deletions src/tar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { ToolRunner } from "@actions/exec/lib/toolrunner";
import * as toolcache from "@actions/tool-cache";
import { safeWhich } from "@chrisgavin/safe-which";

import { Logger } from "./logging";
import { assertNever } from "./util";

const MIN_REQUIRED_BSD_TAR_VERSION = "3.4.3";
const MIN_REQUIRED_GNU_TAR_VERSION = "1.31";

type TarVersion = {
type: "gnu" | "bsd";
version: string;
};

async function getTarVersion(): Promise<TarVersion> {
const tar = await safeWhich("tar");
let stdout = "";
const exitCode = await new ToolRunner(tar, ["--version"], {
listeners: {
stdout: (data: Buffer) => {
stdout += data.toString();
},
},
}).exec();
if (exitCode !== 0) {
throw new Error("Failed to call tar --version");
}
// Return whether this is GNU tar or BSD tar, and the version number
if (stdout.includes("GNU tar")) {
const match = stdout.match(/tar \(GNU tar\) ([0-9.]+)/);
if (!match || !match[1]) {
throw new Error("Failed to parse output of tar --version.");
}

return { type: "gnu", version: match[1] };
} else if (stdout.includes("bsdtar")) {
const match = stdout.match(/bsdtar ([0-9.]+)/);
if (!match || !match[1]) {
throw new Error("Failed to parse output of tar --version.");
}

return { type: "bsd", version: match[1] };
} else {
throw new Error("Unknown tar version");
}
}

export async function isZstdAvailable(logger: Logger): Promise<boolean> {
try {
const { type, version } = await getTarVersion();
logger.info(`Found ${type} tar version ${version}.`);
switch (type) {
case "gnu":
return version >= MIN_REQUIRED_GNU_TAR_VERSION;
case "bsd":
return version >= MIN_REQUIRED_BSD_TAR_VERSION;
default:
assertNever(type);
}
} catch (e) {
logger.error(
"Failed to determine tar version, therefore will assume zstd may not be available. " +
`The underlying error was: ${e}`,
);
return false;
}
}

export type CompressionMethod = "gzip" | "zstd";

export async function extract(path: string): Promise<{
compressionMethod: CompressionMethod;
outputPath: string;
}> {
if (path.endsWith(".tar.gz")) {
return {
compressionMethod: "gzip",
// While we could also ask tar to autodetect the compression method,
// we defensively keep the gzip call identical as requesting a gzipped
// bundle will soon be a fallback option.
outputPath: await toolcache.extractTar(path),
};
}
return {
compressionMethod: "zstd",
// By specifying only the "x" flag, we ask tar to autodetect the compression
// method.
outputPath: await toolcache.extractTar(path, undefined, "x"),
};
}

0 comments on commit ffa1b05

Please sign in to comment.