UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

101 lines 5.47 kB
"use strict"; 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