renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
151 lines (150 loc) • 6.49 kB
JavaScript
import { getEnv } from "../../../util/env.js";
import { logger } from "../../../logger/index.js";
import { coerceArray } from "../../../util/array.js";
import { findLocalSiblingOrParent, readLocalFile } from "../../../util/fs/index.js";
import api from "../../versioning/cargo/index.js";
import { CargoConfig, CargoManifest } from "./schema.js";
import { extractLockFileVersions } from "./locked-version.js";
import { DEFAULT_REGISTRY_URL } from "./utils.js";
import { isObject, isString } from "@sindresorhus/is";
//#region lib/modules/manager/cargo/extract.ts
const DEFAULT_REGISTRY_ID = "crates-io";
function getCargoIndexEnv(registryName) {
const registry = registryName.toUpperCase().replaceAll("-", "_");
return 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 !== DEFAULT_REGISTRY_URL) registryUrls = [registryUrl];
} else dep.skipReason = "unknown-registry";
}
if (registryUrls) dep.registryUrls = registryUrls;
else if (cargoRegistries[DEFAULT_REGISTRY_ID]) {
if (cargoRegistries[DEFAULT_REGISTRY_ID] !== DEFAULT_REGISTRY_URL) dep.registryUrls = [cargoRegistries[DEFAULT_REGISTRY_ID]];
} else 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 readLocalFile(path, "utf8");
if (payload) {
const parsedCargoConfig = CargoConfig.safeParse(payload);
if (parsedCargoConfig.success) return parsedCargoConfig.data;
else logger.debug({
err: parsedCargoConfig.error,
path
}, `Error parsing cargo config`);
}
}
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 = {};
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 = /* @__PURE__ */ new Set()) {
const replacementName = config.source?.[registryName]?.["replace-with"];
if (replacementName) {
logger.debug(`Replacing index of cargo registry ${registryName} with ${replacementName}`);
if (originalNames.has(replacementName)) {
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.debug(`Replacing cargo source registry with ${sourceRegistry} for ${registryName}`);
return sourceRegistry;
}
const registryIndex = config.registries?.[registryName]?.index;
if (registryIndex) return registryIndex;
else if (registryName === DEFAULT_REGISTRY_ID) return DEFAULT_REGISTRY_URL;
else {
logger.debug(`${registryName} cargo registry is missing index`);
return null;
}
}
async function extractPackageFile(content, packageFile, _config) {
logger.trace(`cargo.extractPackageFile(${packageFile})`);
const cargoRegistries = extractCargoRegistries(await readCargoConfig() ?? {});
const parsedCargoManifest = CargoManifest.safeParse(content);
if (!parsedCargoManifest.success) {
logger.debug({
err: parsedCargoManifest.error,
packageFile
}, "Error parsing Cargo.toml file");
return null;
}
const cargoManifest = parsedCargoManifest.data;
const targetSection = cargoManifest.target;
let targetDeps = [];
if (targetSection) Object.keys(targetSection).forEach((target) => {
const targetContent = targetSection[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, void 0);
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 = void 0;
if (packageSection) {
if (isString(packageSection.version)) version = packageSection.version;
else if (isObject(packageSection.version) && cargoManifest.workspace?.package?.version) version = cargoManifest.workspace.package.version;
}
const lockFileName = await findLocalSiblingOrParent(packageFile, "Cargo.lock");
const res = {
deps,
packageFileVersion: version
};
if (lockFileName) {
logger.debug(`Found lock file ${lockFileName} for packageFile: ${packageFile}`);
const versionsByPackage = await extractLockFileVersions(lockFileName);
if (!versionsByPackage) {
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 = coerceArray(versionsByPackage.get(packageName));
let lockedVersion = null;
if (dep.currentValue) lockedVersion = api.getSatisfyingVersion(versions, dep.currentValue);
if (lockedVersion) dep.lockedVersion = lockedVersion;
else logger.debug(`No locked version found for package ${dep.depName} in the range of ${dep.currentValue}.`);
}
}
return res;
}
//#endregion
export { extractPackageFile };
//# sourceMappingURL=extract.js.map