UNPKG

@snyk/java-call-graph-builder

Version:

Tool for building a call graph for JVM ecosystem (Maven, Gradle...)

91 lines 4.14 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getCallGraph = exports.getClassPerJarMapping = exports.getCallGraphGenCommandArgs = void 0; const tslib_1 = require("tslib"); require("source-map-support/register"); const jszip = require("jszip"); const path = require("path"); const config = require("./config"); const sub_process_1 = require("./sub-process"); const fetch_snyk_java_call_graph_generator_1 = require("./fetch-snyk-java-call-graph-generator"); const call_graph_1 = require("./call-graph"); const promisifedFs = require("./promisified-fs-glob"); const promisified_fs_glob_1 = require("./promisified-fs-glob"); const class_parsing_1 = require("./class-parsing"); const metrics_1 = require("./metrics"); const tempDir = require("temp-dir"); function getCallGraphGenCommandArgs(classPath, jarPath, targets) { return [ '-cp', jarPath, 'io.snyk.callgraph.app.App', '--application-classpath-file', classPath, '--dirs-to-get-entrypoints', targets.join(','), ]; } exports.getCallGraphGenCommandArgs = getCallGraphGenCommandArgs; function getClassPerJarMapping(classPath) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const classPerJarMapping = {}; for (const classPathItem of classPath.split(path.delimiter)) { // classpath can also contain local directories with classes - we don't need them for package mapping if (!classPathItem.endsWith('.jar')) { continue; } const jarFileContent = yield promisified_fs_glob_1.readFile(classPathItem); const jarContent = yield jszip.loadAsync(jarFileContent); for (const classFile of Object.keys(jarContent.files).filter((name) => name.endsWith('.class'))) { const className = class_parsing_1.toFQclassName(classFile.replace('.class', '')); // removing .class from name classPerJarMapping[className] = classPathItem; } } return classPerJarMapping; }); } exports.getClassPerJarMapping = getClassPerJarMapping; function getCallGraph(classPath, targetPath, targets, timeout) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const [jarPath, { tmpDir, classPathFile }] = yield Promise.all([ fetch_snyk_java_call_graph_generator_1.fetch(config.CALL_GRAPH_GENERATOR_URL, config.CALL_GRAPH_GENERATOR_CHECKSUM), writeClassPathToTempDir(classPath), ]); const callgraphGenCommandArgs = getCallGraphGenCommandArgs(classPathFile, jarPath, targets); try { const [javaOutput, classPerJarMapping] = yield Promise.all([ metrics_1.timeIt('generateCallGraph', () => sub_process_1.execute('java', callgraphGenCommandArgs, { cwd: targetPath, timeout, })), metrics_1.timeIt('mapClassesPerJar', () => getClassPerJarMapping(classPath)), ]); return call_graph_1.buildCallGraph(javaOutput, classPerJarMapping); } finally { // Fire and forget - we don't have to wait for a deletion of a temporary file cleanupTempDir(classPathFile, tmpDir); } }); } exports.getCallGraph = getCallGraph; function writeClassPathToTempDir(classPath) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const tmpDir = yield promisifedFs.mkdtemp(path.join(tempDir, 'call-graph-generator')); const classPathFile = path.join(tmpDir, 'callgraph-classpath'); yield promisifedFs.writeFile(classPathFile, classPath); return { tmpDir, classPathFile }; }); } function cleanupTempDir(classPathFile, tmpDir) { return tslib_1.__awaiter(this, void 0, void 0, function* () { try { yield promisifedFs.unlink(classPathFile); yield promisifedFs.rmdir(tmpDir); } catch (_a) { // we couldn't delete temporary data in temporary folder, no big deal } }); } //# sourceMappingURL=java-wrapper.js.map