Only try zstd for specified version ranges of tar

This commit is contained in:
Henry Mercer
2024-08-16 12:13:03 +01:00
parent 59c874ecee
commit 3e870d5ac3
12 changed files with 319 additions and 136 deletions

21
lib/codeql.js generated
View File

@@ -45,7 +45,7 @@ const cli_errors_1 = require("./cli-errors");
const doc_url_1 = require("./doc-url");
const environment_1 = require("./environment");
const feature_flags_1 = require("./feature-flags");
const setupCodeql = __importStar(require("./setup-codeql"));
const setup_codeql_1 = require("./setup-codeql");
const tools_features_1 = require("./tools-features");
const tracer_config_1 = require("./tracer-config");
const util = __importStar(require("./util"));
@@ -105,23 +105,6 @@ exports.CODEQL_VERSION_SUBLANGUAGE_FILE_COVERAGE = "2.15.0";
* Versions 2.15.2+ of the CodeQL CLI support the `--sarif-include-query-help` option.
*/
const CODEQL_VERSION_INCLUDE_QUERY_HELP = "2.15.2";
async function setupCodeQLBundlePreferringZstd(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, features, logger) {
let zstdError = undefined;
if (!toolsInput && (await features.getValue(feature_flags_1.Feature.ZstdBundle))) {
try {
return await setupCodeql.setupCodeQLBundle(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, true, logger);
}
catch (e) {
logger.info("Failed to set up bundle compressed using zstd, falling back to bundle compressed using gzip.");
zstdError = e;
}
}
const result = await setupCodeql.setupCodeQLBundle(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, false, logger);
if (zstdError) {
result.toolsDownloadStatusReport = Object.assign({}, result.toolsDownloadStatusReport, { zstdError: (0, util_1.wrapError)(zstdError).message });
}
return result;
}
/**
* Set up CodeQL CLI access.
*
@@ -137,7 +120,7 @@ async function setupCodeQLBundlePreferringZstd(toolsInput, apiDetails, tempDir,
*/
async function setupCodeQL(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, features, logger, checkVersion) {
try {
const { codeqlFolder, toolsDownloadStatusReport, toolsSource, toolsVersion, } = await setupCodeQLBundlePreferringZstd(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, features, logger);
const { codeqlFolder, toolsDownloadStatusReport, toolsSource, toolsVersion, } = await (0, setup_codeql_1.setupCodeQLBundle)(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, features, logger);
logger.debug(`Bundle download status report: ${JSON.stringify(toolsDownloadStatusReport)}`);
let codeqlCmd = path.join(codeqlFolder, "codeql", "codeql");
if (process.platform === "win32") {

File diff suppressed because one or more lines are too long

58
lib/setup-codeql.js generated
View File

@@ -48,6 +48,8 @@ const api = __importStar(require("./api-client"));
// creation scripts. Ensure that any changes to the format of this file are compatible with both of
// these dependents.
const defaults = __importStar(require("./defaults.json"));
const feature_flags_1 = require("./feature-flags");
const tar = __importStar(require("./tar"));
const util = __importStar(require("./util"));
const util_1 = require("./util");
var ToolsSource;
@@ -401,7 +403,7 @@ const downloadCodeQL = async function (codeqlURL, maybeBundleVersion, maybeCliVe
logger.debug(`Finished downloading CodeQL bundle to ${archivedBundlePath} (${downloadDurationMs} ms).`);
logger.debug("Extracting CodeQL bundle.");
const extractionStart = perf_hooks_1.performance.now();
const { compressionMethod, extractedBundlePath } = await extractBundle(archivedBundlePath);
const { compressionMethod, outputPath: extractedBundlePath } = await tar.extract(archivedBundlePath);
const extractionDurationMs = Math.round(perf_hooks_1.performance.now() - extractionStart);
logger.debug(`Finished extracting CodeQL bundle to ${extractedBundlePath} (${extractionDurationMs} ms).`);
await cleanUpGlob(archivedBundlePath, "CodeQL bundle archive", logger);
@@ -467,13 +469,12 @@ function getCanonicalToolcacheVersion(cliVersion, bundleVersion, logger) {
return cliVersion;
}
/**
* Obtains the CodeQL bundle, installs it in the toolcache if appropriate, and extracts it.
* Sets up a CodeQL bundle.
*
* @param checkVersion Whether to check that CodeQL CLI meets the minimum
* version requirement. Must be set to true outside tests.
* @returns the path to the extracted bundle, and the version of the tools
* If `useZstdBundle` is true, and the requested CodeQL bundle needs to be downloaded,
* this function will attempt to download a zstd-compressed bundle.
*/
async function setupCodeQLBundle(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, useZstdBundle, logger) {
async function setupCodeQLBundleWithZstdOption(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, useZstdBundle, logger) {
const source = await getCodeQLSource(toolsInput, defaultCliVersion, apiDetails, variant, useZstdBundle, logger);
let codeqlFolder;
let toolsVersion = source.toolsVersion;
@@ -502,6 +503,35 @@ async function setupCodeQLBundle(toolsInput, apiDetails, tempDir, variant, defau
}
return { codeqlFolder, toolsDownloadStatusReport, toolsSource, toolsVersion };
}
/**
* Obtains the CodeQL bundle, installs it in the toolcache if appropriate, and extracts it.
*
* @returns the path to the extracted bundle, and the version of the tools
*/
async function setupCodeQLBundle(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, features, logger) {
let zstdError = undefined;
if (!toolsInput && (await features.getValue(feature_flags_1.Feature.ZstdBundle))) {
try {
if (await tar.isZstdAvailable(logger)) {
return await setupCodeQLBundleWithZstdOption(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, true, logger);
}
else {
logger.debug("Falling back to bundle compressed using gzip because the available version of tar was not " +
"recognized or is too old.");
}
}
catch (e) {
logger.info("Failed to set up bundle compressed using zstd, falling back to bundle compressed using gzip.");
logger.debug(`Underlying error: ${e}`);
zstdError = e;
}
}
const result = await setupCodeQLBundleWithZstdOption(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, false, logger);
if (zstdError) {
result.toolsDownloadStatusReport = Object.assign({}, result.toolsDownloadStatusReport, { zstdError: (0, util_1.wrapError)(zstdError).message });
}
return result;
}
async function cleanUpGlob(glob, name, logger) {
logger.debug(`Cleaning up ${name}.`);
try {
@@ -520,20 +550,4 @@ async function cleanUpGlob(glob, name, logger) {
logger.warning(`Failed to clean up ${name}: ${e}.`);
}
}
async function extractBundle(archivedBundlePath) {
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"),
};
}
//# sourceMappingURL=setup-codeql.js.map

File diff suppressed because one or more lines are too long

View File

@@ -124,7 +124,7 @@ ava_1.default.beforeEach(() => {
});
await (0, util_1.withTmpDir)(async (tmpDir) => {
(0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir);
const result = await setupCodeql.setupCodeQLBundle("linked", testing_utils_1.SAMPLE_DOTCOM_API_DETAILS, "tmp/codeql_action_test/", util_1.GitHubVariant.DOTCOM, testing_utils_1.SAMPLE_DEFAULT_CLI_VERSION, false, logger);
const result = await setupCodeql.setupCodeQLBundle("linked", testing_utils_1.SAMPLE_DOTCOM_API_DETAILS, "tmp/codeql_action_test/", util_1.GitHubVariant.DOTCOM, testing_utils_1.SAMPLE_DEFAULT_CLI_VERSION, (0, testing_utils_1.createFeatures)([]), logger);
// Basic sanity check that the version we got back is indeed
// the linked (default) CLI version.
t.is(result.toolsVersion, testing_utils_1.LINKED_CLI_VERSION.cliVersion);
@@ -152,7 +152,7 @@ ava_1.default.beforeEach(() => {
});
await (0, util_1.withTmpDir)(async (tmpDir) => {
(0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir);
const result = await setupCodeql.setupCodeQLBundle(bundleUrl, testing_utils_1.SAMPLE_DOTCOM_API_DETAILS, "tmp/codeql_action_test/", util_1.GitHubVariant.DOTCOM, testing_utils_1.SAMPLE_DEFAULT_CLI_VERSION, false, logger);
const result = await setupCodeql.setupCodeQLBundle(bundleUrl, testing_utils_1.SAMPLE_DOTCOM_API_DETAILS, "tmp/codeql_action_test/", util_1.GitHubVariant.DOTCOM, testing_utils_1.SAMPLE_DEFAULT_CLI_VERSION, (0, testing_utils_1.createFeatures)([]), logger);
// Basic sanity check that the version we got back is indeed the version that the
// bundle contains..
t.is(result.toolsVersion, expectedVersion);

File diff suppressed because one or more lines are too long

102
lib/tar.js generated Normal file
View File

@@ -0,0 +1,102 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isZstdAvailable = isZstdAvailable;
exports.extract = extract;
const toolrunner_1 = require("@actions/exec/lib/toolrunner");
const toolcache = __importStar(require("@actions/tool-cache"));
const safe_which_1 = require("@chrisgavin/safe-which");
const util_1 = require("./util");
const MIN_REQUIRED_BSD_TAR_VERSION = "3.4.3";
const MIN_REQUIRED_GNU_TAR_VERSION = "1.31";
async function getTarVersion() {
const tar = await (0, safe_which_1.safeWhich)("tar");
let stdout = "";
const exitCode = await new toolrunner_1.ToolRunner(tar, ["--version"], {
listeners: {
stdout: (data) => {
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");
}
}
async function isZstdAvailable(logger) {
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:
(0, util_1.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;
}
}
async function extract(path) {
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"),
};
}
//# sourceMappingURL=tar.js.map

1
lib/tar.js.map Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"tar.js","sourceRoot":"","sources":["../src/tar.ts"],"names":[],"mappings":"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"}