UNPKG

snyk-poetry-lockfile-parser

Version:

Generate a dep graph given poetry.lock and pyproject.toml files

78 lines 2.98 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.build = build; const lodash_1 = require("lodash"); const dep_graph_1 = require("@snyk/dep-graph"); // Poetry uses the virtualenv to create an environment and this comes with these // packages pre-installed, therefore they won't be part of the lockfile. // See: https://github.com/python-poetry/poetry/issues/3075#issuecomment-703334427 const IGNORED_DEPENDENCIES = [ 'setuptools', 'distribute', 'pip', 'wheel', ]; const DEFAULT_ROOT_PKG = { name: '_root', version: '0.0.0', }; function build(pkgDetails, dependencies, pkgSpecs) { const rootPkg = (0, lodash_1.defaults)({}, pkgDetails, DEFAULT_ROOT_PKG); const builder = new dep_graph_1.DepGraphBuilder({ name: 'poetry' }, rootPkg); addDependenciesToGraph(dependencies, pkgSpecs, builder.rootNodeId, builder); return builder.build(); } function addDependenciesToGraph(dependencies, pkgSpecs, parentNodeId, builder) { for (const dep of dependencies) { addDependenciesForPkg(dep, pkgSpecs, parentNodeId, builder); } } function addDependenciesForPkg(dependency, pkgSpecs, parentNodeId, builder) { const pkgName = dependency.name; if (IGNORED_DEPENDENCIES.includes(pkgName)) { return; } const pkg = pkgLockInfoFor(pkgName, pkgSpecs); if (!pkg) { return; } if (isPkgAlreadyInGraph(pkg, builder)) { builder.connectDep(parentNodeId, pkg.name); return; } const pkgInfo = { name: pkg.name, version: pkg.version }; const labels = { scope: dependency.isDev ? 'dev' : 'prod', }; if (pkg.name != pkgName) { labels.pkgIdProvenance = `${pkgName}@${pkg.version}`; } builder .addPkgNode(pkgInfo, pkg.name, { labels, }) .connectDep(parentNodeId, pkg.name); addDependenciesToGraph(pkg.dependencies.map((dep) => ({ name: dep, isDev: dependency.isDev, })), pkgSpecs, pkg.name, builder); } function isPkgAlreadyInGraph(pkg, builder) { return builder .getPkgs() .some((existingPkg) => existingPkg.name === pkg.name && existingPkg.version === pkg.version); } function pkgLockInfoFor(pkgName, pkgSpecs) { // From PEP 426 https://www.python.org/dev/peps/pep-0426/#name // All comparisons of distribution names MUST be case insensitive, and MUST // consider hyphens and underscores to be equivalent const pkgLockInfo = pkgSpecs.find((lockItem) => lockItem.name.toLowerCase().replace(/_/g, '-') === pkgName.toLowerCase().replace(/_/g, '-') || lockItem.name.toLowerCase().replace(/-/g, '_') === pkgName.toLowerCase().replace(/-/g, '_')); if (!pkgLockInfo) { console.warn(`Could not find any lockfile metadata for package: ${pkgName}. This package will not be represented in the dependency graph.`); } return pkgLockInfo; } //# sourceMappingURL=poetry-dep-graph-builder.js.map