renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
211 lines • 8.89 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractPackageFile = extractPackageFile;
const tslib_1 = require("tslib");
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
const logger_1 = require("../../../logger");
const array_1 = require("../../../util/array");
const env_1 = require("../../../util/env");
const fs_1 = require("../../../util/fs");
const cargo_1 = require("../../versioning/cargo");
const locked_version_1 = require("./locked-version");
const schema_1 = require("./schema");
const utils_1 = require("./utils");
const DEFAULT_REGISTRY_ID = 'crates-io';
function getCargoIndexEnv(registryName) {
const registry = registryName.toUpperCase().replaceAll('-', '_');
return (0, env_1.getEnv)()[`CARGO_REGISTRIES_${registry}_INDEX`] ?? null;
}
function extractFromSection(dependencies, cargoRegistries, target) {
if (!dependencies) {
return [];
}
const deps = [];
for (const dep of Object.values(dependencies)) {
let registryUrls;
if (dep.managerData?.registryName) {
const registryUrl = getCargoIndexEnv(dep.managerData.registryName) ??
cargoRegistries[dep.managerData?.registryName];
if (registryUrl) {
if (registryUrl !== utils_1.DEFAULT_REGISTRY_URL) {
registryUrls = [registryUrl];
}
}
else {
dep.skipReason = 'unknown-registry';
}
}
if (registryUrls) {
dep.registryUrls = registryUrls;
}
else {
// if we don't have an explicit registry URL check if the default registry has a non-standard url
if (cargoRegistries[DEFAULT_REGISTRY_ID]) {
if (cargoRegistries[DEFAULT_REGISTRY_ID] !== utils_1.DEFAULT_REGISTRY_URL) {
dep.registryUrls = [cargoRegistries[DEFAULT_REGISTRY_ID]];
}
}
else {
// we always expect to have DEFAULT_REGISTRY_ID set, if it's not it means the config defines an alternative
// registry that we couldn't resolve.
dep.skipReason = 'unknown-registry';
}
}
if (target) {
dep.target = target;
}
deps.push(dep);
}
return deps;
}
/** Reads `.cargo/config.toml`, or, if not found, `.cargo/config` */
async function readCargoConfig() {
for (const configName of ['config.toml', 'config']) {
const path = `.cargo/${configName}`;
const payload = await (0, fs_1.readLocalFile)(path, 'utf8');
if (payload) {
const parsedCargoConfig = schema_1.CargoConfigSchema.safeParse(payload);
if (parsedCargoConfig.success) {
return parsedCargoConfig.data;
}
else {
logger_1.logger.debug({ err: parsedCargoConfig.error, path }, `Error parsing cargo config`);
}
}
}
logger_1.logger.debug('Neither .cargo/config nor .cargo/config.toml found');
return null;
}
/** Extracts a map of cargo registries from a CargoConfig */
function extractCargoRegistries(config) {
const result = {};
// check if we're overriding our default registry index
result[DEFAULT_REGISTRY_ID] = resolveRegistryIndex(DEFAULT_REGISTRY_ID, config);
const registryNames = new Set([
...Object.keys(config.registries ?? {}),
...Object.keys(config.source ?? {}),
]);
for (const registryName of registryNames) {
result[registryName] = resolveRegistryIndex(registryName, config);
}
return result;
}
function resolveRegistryIndex(registryName, config, originalNames = new Set()) {
// if we have a source replacement, follow that.
// https://doc.rust-lang.org/cargo/reference/source-replacement.html
const replacementName = config.source?.[registryName]?.['replace-with'];
if (replacementName) {
logger_1.logger.debug(`Replacing index of cargo registry ${registryName} with ${replacementName}`);
if (originalNames.has(replacementName)) {
logger_1.logger.warn({ registryName }, 'cargo registry resolves to itself');
return null;
}
return resolveRegistryIndex(replacementName, config, originalNames.add(replacementName));
}
const sourceRegistry = config.source?.[registryName]?.registry;
if (sourceRegistry) {
logger_1.logger.debug(`Replacing cargo source registry with ${sourceRegistry} for ${registryName}`);
return sourceRegistry;
}
const registryIndex = config.registries?.[registryName]?.index;
if (registryIndex) {
return registryIndex;
}
else {
// we don't need an explicit index if we're using the default registry
if (registryName === DEFAULT_REGISTRY_ID) {
return utils_1.DEFAULT_REGISTRY_URL;
}
else {
logger_1.logger.debug(`${registryName} cargo registry is missing index`);
return null;
}
}
}
async function extractPackageFile(content, packageFile, _config) {
logger_1.logger.trace(`cargo.extractPackageFile(${packageFile})`);
const cargoConfig = (await readCargoConfig()) ?? {};
const cargoRegistries = extractCargoRegistries(cargoConfig);
const parsedCargoManifest = schema_1.CargoManifestSchema.safeParse(content);
if (!parsedCargoManifest.success) {
logger_1.logger.debug({ err: parsedCargoManifest.error, packageFile }, 'Error parsing Cargo.toml file');
return null;
}
const cargoManifest = parsedCargoManifest.data;
/*
There are the following sections in Cargo.toml:
[package]
[dependencies]
[dev-dependencies]
[build-dependencies]
[target.*.dependencies]
[workspace.dependencies]
*/
const targetSection = cargoManifest.target;
// An array of all dependencies in the target section
let targetDeps = [];
if (targetSection) {
const targets = Object.keys(targetSection);
targets.forEach((target) => {
const targetContent = targetSection[target];
// Dependencies for `${target}`
const deps = [
...extractFromSection(targetContent.dependencies, cargoRegistries, target),
...extractFromSection(targetContent['dev-dependencies'], cargoRegistries, target),
...extractFromSection(targetContent['build-dependencies'], cargoRegistries, target),
];
targetDeps = targetDeps.concat(deps);
});
}
const workspaceSection = cargoManifest.workspace;
let workspaceDeps = [];
if (workspaceSection) {
workspaceDeps = extractFromSection(workspaceSection.dependencies, cargoRegistries, undefined);
}
const deps = [
...extractFromSection(cargoManifest.dependencies, cargoRegistries),
...extractFromSection(cargoManifest['dev-dependencies'], cargoRegistries),
...extractFromSection(cargoManifest['build-dependencies'], cargoRegistries),
...targetDeps,
...workspaceDeps,
];
if (!deps.length) {
return null;
}
const packageSection = cargoManifest.package;
let version = undefined;
if (packageSection) {
if (is_1.default.string(packageSection.version)) {
version = packageSection.version;
}
else if (is_1.default.object(packageSection.version) &&
cargoManifest.workspace?.package?.version) {
// TODO: Support reading from parent workspace manifest?
version = cargoManifest.workspace.package.version;
}
}
const lockFileName = await (0, fs_1.findLocalSiblingOrParent)(packageFile, 'Cargo.lock');
const res = { deps, packageFileVersion: version };
if (lockFileName) {
logger_1.logger.debug(`Found lock file ${lockFileName} for packageFile: ${packageFile}`);
const versionsByPackage = await (0, locked_version_1.extractLockFileVersions)(lockFileName);
if (!versionsByPackage) {
logger_1.logger.debug(`Could not extract lock file versions from ${lockFileName}.`);
return res;
}
res.lockFiles = [lockFileName];
for (const dep of deps) {
const packageName = dep.packageName ?? dep.depName;
const versions = (0, array_1.coerceArray)(versionsByPackage.get(packageName));
const lockedVersion = cargo_1.api.getSatisfyingVersion(versions, dep.currentValue);
if (lockedVersion) {
dep.lockedVersion = lockedVersion;
}
else {
logger_1.logger.debug(`No locked version found for package ${dep.depName} in the range of ${dep.currentValue}.`);
}
}
}
return res;
}
//# sourceMappingURL=extract.js.map