snyk-poetry-lockfile-parser
Version:
Generate a dep graph given poetry.lock and pyproject.toml files
78 lines • 2.98 kB
JavaScript
;
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