UNPKG

renovate

Version:

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

203 lines (202 loc) • 8.29 kB
import { logger } from "../../../logger/index.js"; import { coerceArray } from "../../../util/array.js"; import { ensureLocalPath } from "../../../util/fs/util.js"; import { readLocalFile } from "../../../util/fs/index.js"; import { extractPackageFile as extractPackageFile$1 } from "../pip_requirements/extract.js"; import { extractPackageFile as extractPackageFile$2 } from "../pep621/extract.js"; import { extractPackageFile as extractPackageFile$3 } from "../pip_setup/extract.js"; import "../pip_setup/index.js"; import { extractHeaderCommand, matchManager } from "./common.js"; import { generateMermaidGraph, inferCommandExecDir, sortPackageFiles } from "./utils.js"; import upath from "upath"; //#region lib/modules/manager/pip-compile/extract.ts async function extractPackageFile(content, packageFile, _config) { logger.trace("pip-compile.extractPackageFile()"); const manager = matchManager(packageFile); switch (manager) { case "pip_setup": return extractPackageFile$3(content, packageFile, _config); case "pip_requirements": return extractPackageFile$1(content); case "pep621": return await extractPackageFile$2(content, packageFile, _config); case "unknown": logger.warn({ packageFile }, `pip-compile: could not determine manager for source file`); return null; default: logger.warn({ packageFile, manager }, `pip-compile: support for manager is not yet implemented`); return null; } } async function extractAllPackageFiles(config, matchedFiles) { logger.trace("pip-compile.extractAllPackageFiles()"); const lockFileArgs = /* @__PURE__ */ new Map(); const depsBetweenFiles = []; const packageFiles = /* @__PURE__ */ new Map(); const lockFileSources = /* @__PURE__ */ new Map(); for (const matchedFile of matchedFiles) { const fileContent = await readLocalFile(matchedFile, "utf8"); if (!fileContent) { logger.debug(`pip-compile: no content found for file ${matchedFile}`); continue; } let compileArgs; let compileDir; try { compileArgs = extractHeaderCommand(fileContent, matchedFile); compileDir = inferCommandExecDir(matchedFile, compileArgs.outputFile); } catch (error) { logger.warn({ matchedFile, errorMessage: error.message }, "pip-compile error"); continue; } lockFileArgs.set(matchedFile, compileArgs); for (const constraint of coerceArray(compileArgs.constraintsFiles)) depsBetweenFiles.push({ sourceFile: constraint, outputFile: matchedFile, type: "constraint" }); for (const override of coerceArray(compileArgs.overridesFiles)) depsBetweenFiles.push({ sourceFile: override, outputFile: matchedFile, type: "override" }); const lockedDeps = extractPackageFile$1(fileContent)?.deps; if (!lockedDeps) { logger.debug({ matchedFile }, "pip-compile: Failed to extract dependencies from lock file"); continue; } for (const relativeSourceFile of compileArgs.sourceFiles) { const packageFile = upath.normalizeTrim(upath.join(compileDir, relativeSourceFile)); try { ensureLocalPath(packageFile); } catch { logger.warn({ matchedFile, packageFile }, "pip-compile: Source file path outside of repository"); continue; } depsBetweenFiles.push({ sourceFile: packageFile, outputFile: matchedFile, type: "requirement" }); if (matchedFiles.includes(packageFile)) { logger.warn({ sourceFile: packageFile, lockFile: matchedFile }, "pip-compile: lock file acts as source file for another lock file"); continue; } if (packageFiles.has(packageFile)) { logger.debug(`pip-compile: ${packageFile} used in multiple output files`); const existingPackageFile = packageFiles.get(packageFile); existingPackageFile.lockFiles.push(matchedFile); extendWithIndirectDeps(existingPackageFile, lockedDeps); const source = lockFileSources.get(matchedFile) ?? []; source.push(existingPackageFile); lockFileSources.set(matchedFile, source); continue; } const content = await readLocalFile(packageFile, "utf8"); if (!content) { logger.debug(`pip-compile: No content for source file ${packageFile}`); continue; } const packageFileContent = await extractPackageFile(content, packageFile, config); if (packageFileContent) { if (packageFileContent.managerData?.requirementsFiles) { packageFileContent.managerData.requirementsFiles = packageFileContent.managerData.requirementsFiles.map((file) => upath.normalize(upath.join(upath.dirname(packageFile), file))); for (const file of packageFileContent.managerData.requirementsFiles) depsBetweenFiles.push({ sourceFile: file, outputFile: packageFile, type: "requirement" }); } if (packageFileContent.managerData?.constraintsFiles) { packageFileContent.managerData.constraintsFiles = packageFileContent.managerData.constraintsFiles.map((file) => upath.normalize(upath.join(compileDir, file))); for (const file of packageFileContent.managerData.constraintsFiles) depsBetweenFiles.push({ sourceFile: file, outputFile: packageFile, type: "requirement" }); } for (const dep of packageFileContent.deps) { const lockedVersion = lockedDeps?.find((lockedDep) => lockedDep.packageName === dep.packageName)?.currentVersion; if (lockedVersion) dep.lockedVersion = lockedVersion; else logger.warn({ depName: dep.depName, lockFile: matchedFile }, "pip-compile: dependency not found in lock file"); } extendWithIndirectDeps(packageFileContent, lockedDeps); const newPackageFile = { ...packageFileContent, lockFiles: [matchedFile], packageFile }; packageFiles.set(packageFile, newPackageFile); const source = lockFileSources.get(matchedFile) ?? []; source.push(newPackageFile); lockFileSources.set(matchedFile, source); } else logger.warn({ packageFile }, "pip-compile: failed to find dependencies in source file"); } } if (packageFiles.size === 0) return null; const result = sortPackageFiles(depsBetweenFiles, packageFiles); for (const packageFile of [...result].reverse()) for (const reqFile of packageFile.managerData?.requirementsFiles ?? []) { let sourceFiles = void 0; if (matchedFiles.includes(reqFile)) sourceFiles = lockFileSources.get(reqFile); else if (packageFiles.has(reqFile)) sourceFiles = [packageFiles.get(reqFile)]; if (!sourceFiles) { logger.warn({ packageFile: packageFile.packageFile, requirementsFile: reqFile }, "pip-compile: Package file references a file which does not appear to be a requirements file managed by pip-compile"); continue; } const files = new Set([...packageFile.lockFiles].reverse()); for (const sourceFile of sourceFiles) { const merged = new Set(files); for (const lockFile of [...sourceFile.lockFiles].reverse()) merged.add(lockFile); sourceFile.lockFiles = Array.from(merged).reverse(); } } logger.debug(`pip-compile: dependency graph:\n${generateMermaidGraph(depsBetweenFiles, lockFileArgs)}`); return result; } function extendWithIndirectDeps(packageFileContent, lockedDeps) { for (const lockedDep of lockedDeps) if (!packageFileContent.deps.find((dep) => lockedDep.packageName === dep.packageName)) packageFileContent.deps.push(indirectDep(lockedDep)); } /** * As indirect dependecies don't exist in the package file, we need to * create them from the lock file. * * By removing currentValue and currentVersion, we ensure that they * are handled like unconstrained dependencies with locked version. * Such packages are updated when their update strategy * is set to 'update-lockfile', * see: lib/workers/repository/process/lookup/index.ts. * * By disabling them by default, we won't create noise by updating them. * Unless they have vulnerability alert, then they are forced to be updated. * @param dep dependency extracted from lock file (requirements.txt) * @returns unconstrained dependency with locked version */ function indirectDep(dep) { const result = { ...dep, lockedVersion: dep.currentVersion, depType: "indirect", enabled: false }; delete result.currentValue; delete result.currentVersion; return result; } //#endregion export { extractAllPackageFiles, extractPackageFile }; //# sourceMappingURL=extract.js.map