renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
100 lines • 4.35 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MSBUILD_CENTRAL_FILE = exports.NUGET_CENTRAL_FILE = void 0;
exports.getDependentPackageFiles = getDependentPackageFiles;
const tslib_1 = require("tslib");
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
const graph_data_structure_1 = require("graph-data-structure");
const upath_1 = tslib_1.__importDefault(require("upath"));
const logger_1 = require("../../../logger");
const minimatch_1 = require("../../../util/minimatch");
const scm_1 = require("../../platform/scm");
const util_1 = require("./util");
exports.NUGET_CENTRAL_FILE = 'Directory.Packages.props';
exports.MSBUILD_CENTRAL_FILE = 'Packages.props';
/**
* Get all leaf package files of ancestry that depend on packageFileName.
*/
async function getDependentPackageFiles(packageFileName, isCentralManagement = false) {
const packageFiles = await getAllPackageFiles();
const graph = new graph_data_structure_1.Graph();
if (isCentralManagement) {
graph.addNode(packageFileName);
}
const parentDir = packageFileName === exports.NUGET_CENTRAL_FILE ||
packageFileName === exports.MSBUILD_CENTRAL_FILE
? ''
: upath_1.default.dirname(packageFileName);
for (const f of packageFiles) {
graph.addNode(f);
if (isCentralManagement && upath_1.default.dirname(f).startsWith(parentDir)) {
graph.addEdge(packageFileName, f);
}
}
for (const f of packageFiles) {
const doc = await (0, util_1.readFileAsXmlDocument)(f);
if (!doc) {
continue;
}
const projectReferenceAttributes = doc
.childrenNamed('ItemGroup')
.map((ig) => ig.childrenNamed('ProjectReference'))
.flat()
.map((pf) => pf.attr.Include)
.filter(is_1.default.nonEmptyString);
const projectReferences = projectReferenceAttributes.map((a) => upath_1.default.normalize(a));
const normalizedRelativeProjectReferences = projectReferences.map((r) => reframeRelativePathToRootOfRepo(f, r));
for (const ref of normalizedRelativeProjectReferences) {
graph.addEdge(ref, f);
}
if ((0, graph_data_structure_1.hasCycle)(graph)) {
throw new Error('Circular reference detected in NuGet package files');
}
}
const deps = new Map();
recursivelyGetDependentPackageFiles(packageFileName, graph, deps);
if (isCentralManagement) {
// remove props file, as we don't need it
deps.delete(packageFileName);
}
// deduplicate
return Array.from(deps).map(([name, isLeaf]) => ({ name, isLeaf }));
}
/**
* Traverse graph and find dependent package files at any level of ancestry
*/
function recursivelyGetDependentPackageFiles(packageFileName, graph, deps) {
if (deps.has(packageFileName)) {
// we have already visited this package file
return;
}
const dependents = graph.adjacent(packageFileName);
if (!dependents || dependents.size === 0) {
deps.set(packageFileName, true);
return;
}
deps.set(packageFileName, false);
for (const dep of dependents) {
recursivelyGetDependentPackageFiles(dep, graph, deps);
}
}
/**
* Take the path relative from a project file, and make it relative from the root of the repo
*/
function reframeRelativePathToRootOfRepo(dependentProjectRelativePath, projectReference) {
const virtualRepoRoot = '/';
const absoluteDependentProjectPath = upath_1.default.resolve(virtualRepoRoot, dependentProjectRelativePath);
const absoluteProjectReferencePath = upath_1.default.resolve(upath_1.default.dirname(absoluteDependentProjectPath), projectReference);
const relativeProjectReferencePath = upath_1.default.relative(virtualRepoRoot, absoluteProjectReferencePath);
return relativeProjectReferencePath;
}
/**
* Get a list of package files in localDir
*/
async function getAllPackageFiles() {
const allFiles = await scm_1.scm.getFileList();
const filteredPackageFiles = allFiles.filter((0, minimatch_1.minimatchFilter)('*.{cs,vb,fs}proj', { matchBase: true, nocase: true }));
logger_1.logger.trace({ filteredPackageFiles }, 'Found package files');
return filteredPackageFiles;
}
//# sourceMappingURL=package-tree.js.map