UNPKG

renovate

Version:

Automated dependency updates. Flexible so you don't need to be.

211 lines • 8.88 kB
"use strict"; 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.CargoConfig.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.CargoManifest.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