UNPKG

@snyk/java-call-graph-builder

Version:

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

116 lines 4.92 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.fetch = exports.JAR_NAME = void 0; const tslib_1 = require("tslib"); const fs = require("fs"); const path = require("path"); const needle = require("needle"); const ciInfo = require("ci-info"); const ProgressBar = require("progress"); const tempDir = require("temp-dir"); const crypto = require("crypto"); const debug_1 = require("./debug"); const metrics = require("./metrics"); const promisifedFs = require("./promisified-fs-glob"); exports.JAR_NAME = 'java-call-graph-generator.jar'; const LOCAL_PATH = path.join(tempDir, 'call-graph-generator', exports.JAR_NAME); function createProgressBar(total, name) { return new ProgressBar(`downloading ${name} [:bar] :rate/Kbps :percent :etas remaining`, { complete: '=', incomplete: '.', width: 20, total: total / 1000, clear: true, }); } function downloadAnalyzer(url, localPath, expectedChecksum) { return tslib_1.__awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { const fsStream = fs.createWriteStream(localPath + '.part'); try { let progressBar; debug_1.debug(`fetching java graph generator from ${url}`); const req = needle.get(url); let matchChecksum; let hasError = false; // TODO: Try pump (https://www.npmjs.com/package/pump) for more organised flow req .on('response', (res) => tslib_1.__awaiter(this, void 0, void 0, function* () { if (res.statusCode >= 400) { const err = new Error('Bad HTTP response for snyk-call-graph-generator download'); // TODO: add custom error for status code => err.statusCode = res.statusCode; fsStream.destroy(); hasError = true; return reject(err); } matchChecksum = verifyChecksum(req, expectedChecksum); debug_1.debug(`downloading ${exports.JAR_NAME} ...`); if (!ciInfo.isCI) { const total = parseInt(res.headers['content-length'], 10); progressBar = createProgressBar(total, exports.JAR_NAME); } })) .on('data', (chunk) => { if (progressBar) { progressBar.tick(chunk.length / 1000); } }) .on('error', (err) => { return reject(err); }) .pipe(fsStream) .on('error', (err) => { fsStream.destroy(); return reject(err); }) .on('finish', () => tslib_1.__awaiter(this, void 0, void 0, function* () { if (hasError) { yield promisifedFs.unlink(localPath + '.part'); } else { if (!(yield matchChecksum)) { return reject(new Error('Wrong checksum of downloaded call-graph-generator.')); } yield promisifedFs.rename(localPath + '.part', localPath); resolve(localPath); } })); } catch (err) { reject(err); } }); }); } function verifyChecksum(localPathStream, expectedChecksum) { return tslib_1.__awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { const hash = crypto.createHash('sha256'); localPathStream .on('error', reject) .on('data', (chunk) => { hash.update(chunk); }) .on('end', () => { resolve(hash.digest('hex') === expectedChecksum); }); }); }); } function fetch(url, expectedChecksum) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const localPath = LOCAL_PATH; if (yield promisifedFs.exists(localPath)) { if (yield verifyChecksum(fs.createReadStream(localPath), expectedChecksum)) { return localPath; } debug_1.debug(`new version of ${exports.JAR_NAME} available`); } if (!(yield promisifedFs.exists(path.dirname(localPath)))) { yield promisifedFs.mkdir(path.dirname(localPath)); } return yield metrics.timeIt('fetchCallGraphBuilder', () => downloadAnalyzer(url, localPath, expectedChecksum)); }); } exports.fetch = fetch; //# sourceMappingURL=fetch-snyk-java-call-graph-generator.js.map