UNPKG

renovate

Version:

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

217 lines • 10.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.extractPackageFile = extractPackageFile; exports.extractAllPackageFiles = extractAllPackageFiles; const tslib_1 = require("tslib"); const upath_1 = tslib_1.__importDefault(require("upath")); const logger_1 = require("../../../logger"); const array_1 = require("../../../util/array"); const fs_1 = require("../../../util/fs"); const util_1 = require("../../../util/fs/util"); const extract_1 = require("../pip_requirements/extract"); const pip_setup_1 = require("../pip_setup"); const common_1 = require("./common"); const utils_1 = require("./utils"); function extractPackageFile(content, packageFile, _config) { logger_1.logger.trace('pip-compile.extractPackageFile()'); const manager = (0, common_1.matchManager)(packageFile); switch (manager) { case 'pip_setup': return (0, pip_setup_1.extractPackageFile)(content, packageFile, _config); case 'pip_requirements': return (0, extract_1.extractPackageFile)(content); case 'unknown': logger_1.logger.warn({ packageFile }, `pip-compile: could not determine manager for source file`); return null; default: logger_1.logger.warn({ packageFile, manager }, `pip-compile: support for manager is not yet implemented`); return null; } } async function extractAllPackageFiles(config, matchedFiles) { logger_1.logger.trace('pip-compile.extractAllPackageFiles()'); const lockFileArgs = new Map(); const depsBetweenFiles = []; const packageFiles = new Map(); const lockFileSources = new Map(); for (const matchedFile of matchedFiles) { const fileContent = await (0, fs_1.readLocalFile)(matchedFile, 'utf8'); if (!fileContent) { logger_1.logger.debug(`pip-compile: no content found for file ${matchedFile}`); continue; } let compileArgs; let compileDir; try { compileArgs = (0, common_1.extractHeaderCommand)(fileContent, matchedFile); compileDir = (0, utils_1.inferCommandExecDir)(matchedFile, compileArgs.outputFile); } catch (error) { logger_1.logger.warn({ matchedFile, errorMessage: error.message }, 'pip-compile error'); continue; } lockFileArgs.set(matchedFile, compileArgs); for (const constraint of (0, array_1.coerceArray)(compileArgs.constraintsFiles)) { depsBetweenFiles.push({ sourceFile: constraint, outputFile: matchedFile, type: 'constraint', }); } const lockedDeps = (0, extract_1.extractPackageFile)(fileContent)?.deps; if (!lockedDeps) { logger_1.logger.debug({ matchedFile }, 'pip-compile: Failed to extract dependencies from lock file'); continue; } for (const relativeSourceFile of compileArgs.sourceFiles) { const packageFile = upath_1.default.normalizeTrim(upath_1.default.join(compileDir, relativeSourceFile)); try { (0, util_1.ensureLocalPath)(packageFile); } catch { logger_1.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)) { // TODO(not7cd): do something about it logger_1.logger.warn({ sourceFile: packageFile, lockFile: matchedFile }, 'pip-compile: lock file acts as source file for another lock file'); continue; } if (packageFiles.has(packageFile)) { logger_1.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 (0, fs_1.readLocalFile)(packageFile, 'utf8'); if (!content) { logger_1.logger.debug(`pip-compile: No content for source file ${packageFile}`); continue; } const packageFileContent = extractPackageFile(content, packageFile, config); if (packageFileContent) { if (packageFileContent.managerData?.requirementsFiles) { packageFileContent.managerData.requirementsFiles = packageFileContent.managerData.requirementsFiles.map((file) => upath_1.default.normalize(upath_1.default.join(compileDir, 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_1.default.normalize(upath_1.default.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_1.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_1.logger.warn({ packageFile }, 'pip-compile: failed to find dependencies in source file'); } } } if (packageFiles.size === 0) { return null; } const result = (0, utils_1.sortPackageFiles)(depsBetweenFiles, packageFiles); // This needs to go in reverse order to handle transitive dependencies for (const packageFile of [...result].reverse()) { for (const reqFile of packageFile.managerData?.requirementsFiles ?? []) { let sourceFiles = undefined; if (matchedFiles.includes(reqFile)) { sourceFiles = lockFileSources.get(reqFile); } else if (packageFiles.has(reqFile)) { sourceFiles = [packageFiles.get(reqFile)]; } if (!sourceFiles) { logger_1.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; } // These get reversed before merging so that we keep the last instance of any common // lock files, since a file that -r includes multiple lock files needs to be updated after // all of the lock files it includes 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_1.logger.debug('pip-compile: dependency graph:\n' + (0, utils_1.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; } //# sourceMappingURL=extract.js.map