@eagleoutice/flowr-dev
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
101 lines • 5.47 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FlowrAnalyzerPackageVersionsLibraryPlugin = exports.libraryLog = void 0;
const flowr_analyzer_package_versions_plugin_1 = require("./flowr-analyzer-package-versions-plugin");
const semver_1 = require("semver");
const package_1 = require("./package");
const flowr_file_1 = require("../../context/flowr-file");
const flowr_description_file_1 = require("../file-plugins/files/flowr-description-file");
const flowr_namespace_file_1 = require("../file-plugins/files/flowr-namespace-file");
const log_1 = require("../../../util/log");
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
exports.libraryLog = log_1.log.getSubLogger({ name: 'flowr-analyzer-package-versions-library-plugin' });
/** the directories below `root` that may hold a library, stopping at an installed package (it holds none) */
function libraryDirs(root, depth) {
if (depth <= 0 || !fs_1.default.existsSync(root)) {
return [];
}
return fs_1.default.readdirSync(root, { withFileTypes: true }).filter(e => e.isDirectory()).flatMap(e => {
const dir = path_1.default.join(root, e.name);
return fs_1.default.existsSync(path_1.default.join(dir, 'DESCRIPTION')) ? [] : [dir, ...libraryDirs(dir, depth - 1)];
});
}
/**
* The library directories to search: the ones configured, or else the ones R's environment names (which
* already are libraries) and a project-local `renv`/`packrat` one (which nests its library below a platform
* and an R version).
*/
function libraryRoots(opts, projectRoot) {
if (opts.paths?.length) {
return opts.paths;
}
const fromEnv = opts.useEnvironment === false ? [] :
[process.env.R_LIBS_USER, process.env.R_LIBS, process.env.R_LIBS_SITE].flatMap(v => v?.split(path_1.default.delimiter) ?? []);
const local = opts.useProjectLibrary === false || projectRoot === undefined ? [] :
['renv/library', 'renv/staging', 'packrat/lib'].map(d => path_1.default.join(projectRoot, d))
.flatMap(d => [d, ...libraryDirs(d, opts.maxDepth ?? 3)]);
return [...new Set([...fromEnv, ...local])].filter(d => d.length > 0);
}
/**
* The package installed under `name` in one of `roots`, read from its own `DESCRIPTION` and `NAMESPACE`.
* An installed package keeps both, so its exports are recoverable even when no signature database knows it.
*/
function installedPackage(name, roots) {
for (const root of roots) {
const dir = path_1.default.join(root, name);
const description = path_1.default.join(dir, 'DESCRIPTION');
const namespace = path_1.default.join(dir, 'NAMESPACE');
if (!fs_1.default.existsSync(description) || !fs_1.default.existsSync(namespace)) {
continue;
}
try {
const version = new flowr_description_file_1.FlowrDescriptionFile(new flowr_file_1.FlowrTextFile(description)).version();
const namespaceInfo = flowr_namespace_file_1.FlowrNamespaceFile.from(new flowr_file_1.FlowrTextFile(namespace)).content().current;
exports.libraryLog.debug(`Recovered ${name}${version ? ` ${version.str}` : ''} from ${dir}`);
return new package_1.Package({ name, resolvedVersion: version?.str, namespaceInfo });
}
catch (e) {
exports.libraryLog.warn(`Could not read the installed ${name} in ${dir}`, e);
}
}
return undefined;
}
/**
* Fills in packages no signature database knows from the copy installed on this machine: a package that CRAN
* archived (`maptools`, `rgdal`, ...) is in no database, but if it is installed, its `NAMESPACE` states its
* exports just as well. Off unless `solver.sigdb.installedLibrary.enabled` says otherwise, and consulted only
* for a package nothing else could resolve, so it never overrides a database entry.
*/
class FlowrAnalyzerPackageVersionsLibraryPlugin extends flowr_analyzer_package_versions_plugin_1.FlowrAnalyzerPackageVersionsPlugin {
name = 'flowr-analyzer-package-version-library-plugin';
description = 'Recovers the exports of packages no database knows from their installed copy.';
version = new semver_1.SemVer('0.1.0');
overrides;
/** @param overrides - options replacing what `solver.sigdb.installedLibrary` states, `enabled` included */
constructor(overrides) {
super();
this.overrides = overrides;
}
process(ctx) {
const opts = { ...ctx.config.solver.sigdb.installedLibrary, ...this.overrides };
if (!opts.enabled) {
return;
}
const only = opts.packages?.map(p => new RegExp(p)) ?? [];
/* walking the library directories is only worth it once something actually goes unresolved */
let roots;
ctx.deps.addLazyResolver((name, existing) => {
if (existing?.namespaceInfo !== undefined || (only.length > 0 && !only.some(p => p.test(name)))) {
return undefined;
}
roots ??= libraryRoots(opts, ctx.files.root());
return installedPackage(name, roots);
});
}
}
exports.FlowrAnalyzerPackageVersionsLibraryPlugin = FlowrAnalyzerPackageVersionsLibraryPlugin;
//# sourceMappingURL=flowr-analyzer-package-versions-library-plugin.js.map