renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
99 lines (98 loc) • 4.1 kB
JavaScript
import { logger } from "../../../logger/index.js";
import { joinUrlParts } from "../../../util/url.js";
import { toSha256 } from "../../../util/hash.js";
import { createCacheWriteStream, ensureCacheDir, pipeline, rmCache } from "../../../util/fs/index.js";
import "./common.js";
import { computeFileChecksum, parseChecksumsFromInRelease } from "./checksum.js";
import { checkIfModified, getBaseSuiteUrl } from "./url.js";
import { extract, getFileCreationTime } from "./utils.js";
import { randomUUID } from "node:crypto";
import upath from "upath";
//#region lib/modules/datasource/deb/packages.ts
/**
* Downloads and extracts a package file from a component URL.
*
* @param componentUrl - The URL of the component.
* @returns The path to the extracted file and the last modification timestamp.
* @throws Will throw an error if no valid compression method is found.
*/
async function downloadAndExtractPackage(componentUrl, http) {
const packageUrlHash = toSha256(componentUrl);
const fullCacheDir = await ensureCacheDir("deb");
const extractedFile = upath.join(fullCacheDir, `${packageUrlHash}.txt`);
let lastTimestamp = await getFileCreationTime(extractedFile);
const compression = "gz";
const compressedFile = upath.join(fullCacheDir, `${randomUUID()}_${packageUrlHash}.${compression}`);
if (await downloadPackageFile(componentUrl, compression, compressedFile, http, lastTimestamp) || !lastTimestamp) try {
await extract(compressedFile, compression, extractedFile);
lastTimestamp = await getFileCreationTime(extractedFile);
} catch (error) {
logger.warn({
compressedFile,
componentUrl,
compression,
error: error.message
}, "Failed to extract package file from compressed file");
} finally {
await rmCache(compressedFile);
}
if (!lastTimestamp) throw new Error("Missing metadata in extracted package index file!");
return {
extractedFile,
lastTimestamp
};
}
/**
* Downloads a package file if it has been modified since the last download timestamp.
*
* @param basePackageUrl - The base URL of the package.
* @param compression - The compression method used (e.g., 'gz').
* @param compressedFile - The path where the compressed file will be saved.
* @param lastDownloadTimestamp - The timestamp of the last download.
* @returns True if the file was downloaded, otherwise false.
*/
async function downloadPackageFile(basePackageUrl, compression, compressedFile, http, lastDownloadTimestamp) {
const baseSuiteUrl = getBaseSuiteUrl(basePackageUrl);
const packageUrl = joinUrlParts(basePackageUrl, `Packages.${compression}`);
let needsToDownload = true;
if (lastDownloadTimestamp) needsToDownload = await checkIfModified(packageUrl, lastDownloadTimestamp, http);
if (!needsToDownload) {
logger.debug(`No need to download ${packageUrl}, file is up to date.`);
return false;
}
await pipeline(http.stream(packageUrl), createCacheWriteStream(compressedFile));
logger.debug({
url: packageUrl,
targetFile: compressedFile
}, "Downloading Debian package file");
let inReleaseContent = "";
try {
inReleaseContent = await fetchInReleaseFile(baseSuiteUrl, http);
} catch (error) {
logger.debug({
url: baseSuiteUrl,
err: error
}, "Could not fetch InRelease file");
}
if (inReleaseContent) {
if (await computeFileChecksum(compressedFile) !== parseChecksumsFromInRelease(inReleaseContent, packageUrl.replace(`${baseSuiteUrl}/`, ""))) {
await rmCache(compressedFile);
throw new Error("SHA256 checksum validation failed");
}
}
return needsToDownload;
}
/**
* Fetches the content of the InRelease file from the given base suite URL.
*
* @param baseReleaseUrl - The base URL of the suite (e.g., 'https://deb.debian.org/debian/dists/bullseye').
* @returns resolves to the content of the InRelease file.
* @throws An error if the InRelease file could not be downloaded.
*/
async function fetchInReleaseFile(baseReleaseUrl, http) {
const inReleaseUrl = joinUrlParts(baseReleaseUrl, "InRelease");
return (await http.getText(inReleaseUrl)).body;
}
//#endregion
export { downloadAndExtractPackage };
//# sourceMappingURL=packages.js.map