UNPKG

@typescript/analyze-trace

Version:
208 lines 7.82 kB
"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. Object.defineProperty(exports, "__esModule", { value: true }); const cp = require("child_process"); const fs = require("fs"); const os = require("os"); const path = require("path"); const exit = require("exit"); const plimit = require("p-limit"); const yargs = require("yargs"); const analyze_trace_options_1 = require("./analyze-trace-options"); const argv = yargs(process.argv.slice(2)) .command("$0 <traceDir>", "Preprocess tracing type dumps", yargs => yargs .positional("traceDir", { type: "string", desc: "Directory of trace and types files", coerce: throwIfNotDirectory }) .options(analyze_trace_options_1.commandLineOptions) .check(analyze_trace_options_1.checkCommandLineOptions) .help("h").alias("h", "help") .epilog("Exits with code 0 if highlights were found, 1 if no highlights were found, and 2 if an error occurred") .strict()) .argv; // Try to leave one core free const limit = plimit(Math.max(1, os.cpus().length - 1)); const traceDir = argv.traceDir; main() .then(code => exit(code)) .catch(err => { console.error(`Internal Error: ${err.message}`); exit(2); }); async function main() { let projects; const legendPath = path.join(traceDir, "legend.json"); if (await isFile(legendPath)) { try { const legendText = await fs.promises.readFile(legendPath, { encoding: "utf-8" }); projects = JSON.parse(legendText); for (const project of projects) { project.tracePath = path.resolve(traceDir, path.basename(project.tracePath)); project.typesPath = path.resolve(traceDir, path.basename(project.typesPath)); } } catch (e) { console.error(`Error reading legend file: ${e.message}`); } } if (!projects) { projects = []; for (const entry of await fs.promises.readdir(traceDir, { withFileTypes: true })) { if (!entry.isFile()) continue; const name = entry.name; const match = name.match(/^trace(.*\.json)$/); if (match) { projects.push({ tracePath: path.join(traceDir, name), typesPath: path.join(traceDir, `types${match[1]}`), }); } } } const results = await Promise.all(projects.map(p => limit(analyzeProject, p))); return argv.json ? await printResultsAsJson(results) : await printResultsAsText(results); } async function printResultsAsJson(results) { let sawHighlights = false; const hadErrors = []; const hadNoErrors = []; for (const result of results) { if (result.stderr || result.signal) { hadErrors.push(result); continue; } if (result.exitCode) { // 1 just indicates "no highlights" if (result.exitCode !== 1) { hadErrors.push(result); } continue; } try { hadNoErrors.push(Object.assign(Object.assign({}, result), { highlights: JSON.parse(result.stdout) })); sawHighlights = true; } catch (_a) { hadErrors.push(Object.assign(Object.assign({}, result), { stderr: "Failed to parse project result JSON" })); } } const json = { errors: hadErrors.length === 0 ? undefined : hadErrors.map(result => (Object.assign(Object.assign({}, result), { stdout: undefined, stderr: undefined, exitCode: result.exitCode || undefined, message: result.stderr }))), results: hadNoErrors.map(result => ({ project: result.project, highlights: result.highlights, })), }; console.log(JSON.stringify(json, undefined, 2)); return hadErrors.length > 0 ? 2 : sawHighlights ? 0 : 1; } async function printResultsAsText(results) { const hadHighlights = []; const hadErrors = []; for (const result of results) { if (result.stderr || result.signal) { hadErrors.push(result); continue; } if (result.exitCode) { // 1 just indicates "no highlights" if (result.exitCode !== 1) { hadErrors.push(result); } continue; } // First will be the largest, so only need to match one const match = result.stdout.match(/\((\d+)[ ]*ms\)/); const score = match ? +match[1] : 0; // Treat all duplicates as tied for now hadHighlights.push(Object.assign(Object.assign({}, result), { score })); } let first = true; const projectCount = results.length; // Break ties with trace paths for determinism hadHighlights.sort((a, b) => b.score - a.score || a.project.tracePath.localeCompare(b.project.tracePath)); // Descending for (const result of hadHighlights) { if (!first) console.log(); first = false; const project = result.project; if (projectCount > 1 || project.configFilePath) { console.log(`Analyzed ${getProjectDescription(project)}`); } console.log(result.stdout); } for (const errorResult of hadErrors) { if (!first) console.log(); first = false; const project = errorResult.project; console.log(`Error analyzing ${getProjectDescription(project)}`); if (errorResult.stderr) { console.log(errorResult.stderr); } else if (errorResult.exitCode) { console.log(`Exited with code ${errorResult.exitCode}`); } else if (errorResult.signal) { console.log(`Terminated with signal ${errorResult.signal}`); } } const interestingCount = hadHighlights.length + hadErrors.length; if (interestingCount < projectCount) { if (!first) console.log(); first = false; console.log(`Found nothing in ${projectCount - interestingCount}${interestingCount ? " other" : ""} project(s)`); } return hadErrors.length > 0 ? 2 : hadHighlights.length > 0 ? 0 : 1; } function getProjectDescription(project) { return project.configFilePath ? `${project.configFilePath} (${path.basename(project.tracePath)})` : path.basename(project.tracePath); } async function analyzeProject(project) { const args = [project.tracePath]; if (await isFile(project.typesPath)) { args.push(project.typesPath); } (0, analyze_trace_options_1.pushCommandLineOptions)(args, argv); return new Promise(resolve => { const child = cp.fork(path.join(__dirname, "analyze-trace-file"), args, { stdio: "pipe" }); let stdout = ""; let stderr = ""; child.stdout.on("data", chunk => stdout += chunk); child.stderr.on("data", chunk => stderr += chunk); child.on("exit", (code, signal) => { resolve({ project, stdout: stdout.trim(), stderr: stderr.trim(), exitCode: code !== null && code !== void 0 ? code : undefined, signal: signal !== null && signal !== void 0 ? signal : undefined, }); }); }); } function isFile(path) { return fs.promises.stat(path).then(stats => stats.isFile()).catch(_ => false); } function throwIfNotDirectory(path) { var _a; if (!fs.existsSync(path) || !((_a = fs.statSync(path)) === null || _a === void 0 ? void 0 : _a.isDirectory())) { throw new Error(`${path} is not a directory`); } return path; } //# sourceMappingURL=analyze-trace-dir.js.map