UNPKG

@oaklean/profiler-core

Version:

Part of the @oaklean suite. It provides all basic functions to work with the `.oak` file format. It allows parsing the `.oak` file format as well as tools for analyzing the measurement values. It also provides all necessary capabilities required for prec

290 lines 26.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProjectReport = void 0; const fs = __importStar(require("fs")); const NodeModule_1 = require("./NodeModule"); const ProfilerConfig_1 = require("./ProfilerConfig"); const Report_1 = require("./Report"); const SystemInformation_1 = require("./SystemInformation"); const GlobalIndex_1 = require("./indices/GlobalIndex"); const SourceNodeGraph_1 = require("./SourceNodeGraph"); const constants_1 = require("../constants"); const Crypto_1 = require("../system/Crypto"); const BufferHelper_1 = require("../helper/BufferHelper"); const ResolveFunctionIdentifierHelper_1 = require("../helper/ResolveFunctionIdentifierHelper"); const InsertCPUProfileStateMachine_1 = require("../helper/InsertCPUProfileHelper/InsertCPUProfileStateMachine"); // Types const types_1 = require("../types"); class ProjectReport extends Report_1.Report { constructor(executionDetails, kind, projectMetaData, globalIndex, config) { let index = globalIndex; if (index === undefined) { index = new GlobalIndex_1.GlobalIndex(new NodeModule_1.NodeModule(executionDetails.languageInformation.name, executionDetails.languageInformation.version)); } super(index.getModuleIndex('upsert'), kind); this.globalIndex = index; const usedConfig = config !== undefined ? config : ProfilerConfig_1.ProfilerConfig.autoResolve(); this.executionDetails = executionDetails; if (projectMetaData) { this.projectMetaData = projectMetaData; } else { if (usedConfig === null) { throw new Error('ProjectReport: no config was provided'); } this.projectMetaData = { projectID: usedConfig.getProjectIdentifier() }; } } asSourceNodeGraph() { if (this._sourceNodeGraph === undefined) { const graph = SourceNodeGraph_1.SourceNodeGraph.fromProjectReport(this); this._sourceNodeGraph = graph; } return this._sourceNodeGraph; } normalize() { const newGlobalIndex = new GlobalIndex_1.GlobalIndex(this.engineModule); super.normalize(newGlobalIndex); this.globalIndex = newGlobalIndex; } get engineModule() { return this.globalIndex.engineModule; } isCompatibleWith(other) { return this.reportVersion === other.reportVersion; } static merge(moduleIndex, ...args) { if (args.length === 0) { throw new Error('ProjectReport.merge: no ProjectReports were given'); } const sortedReports = [...args].sort((reportA, reportB) => { const compared = BigInt(reportA.executionDetails.highResolutionBeginTime) - BigInt(reportB.executionDetails.highResolutionBeginTime); if (compared > BigInt(0)) { return 1; } else if (compared < BigInt(0)) { return -1; } return 0; }); const systemInformationList = sortedReports.map((x) => x.executionDetails.systemInformation); if (!SystemInformation_1.SystemInformation.sameSystem(...systemInformationList)) { throw new Error('ProjectReport.merge: cannot merge ProjectReports from different systems'); } const executionDetails = sortedReports[0].executionDetails; for (const currentProjectReport of sortedReports) { if (currentProjectReport.executionDetails.commitHash !== executionDetails.commitHash) { throw new Error('ProjectReport.merge: Project reports commit hashs are not the same'); } if (currentProjectReport.executionDetails.origin !== executionDetails.origin) { throw new Error('ProjectReport.merge: Project reports have different origins'); } if (executionDetails.uncommittedChanges || currentProjectReport.executionDetails.uncommittedChanges) { executionDetails.uncommittedChanges = true; } if (currentProjectReport.executionDetails.timestamp < executionDetails.timestamp) { // set execution timestamp to the earliest // if e.g. multiple test reports are merged, the first report marks the first test execution executionDetails.timestamp = currentProjectReport.executionDetails.timestamp; // only keep the system information of the first report executionDetails.systemInformation = currentProjectReport.executionDetails.systemInformation; } } const result = Object.assign(new ProjectReport(executionDetails, types_1.ReportKind.accumulated), Report_1.Report.merge(moduleIndex, ...sortedReports)); result.globalIndex = moduleIndex.globalIndex; return result; } toJSON() { if (constants_1.NODE_ENV === 'test') { this.validate(); } const reportJSON = super.toJSON(); const result = { projectMetaData: this.projectMetaData, executionDetails: this.executionDetails, globalIndex: this.globalIndex.toJSON() }; return Object.assign(result, reportJSON); } static fromJSON(json) { let data; if (typeof json === 'string') { data = JSON.parse(json); } else { data = json; } const projectReport = new ProjectReport(data.executionDetails, data.kind, data.projectMetaData, GlobalIndex_1.GlobalIndex.fromJSON(data.globalIndex, new NodeModule_1.NodeModule(data.executionDetails.languageInformation.name, data.executionDetails.languageInformation.version)), null); const result = Object.assign(projectReport, Report_1.Report.fromJSONReport(data, projectReport.moduleIndex)); return result; } static loadFromFile(filePath, kind) { if (!fs.existsSync(filePath.toPlatformString())) { return undefined; } switch (kind) { case 'json': return ProjectReport.fromJSON(fs.readFileSync(filePath.toPlatformString()).toString()); case 'bin': { const { instance } = ProjectReport.consumeFromBuffer(fs.readFileSync(filePath.toPlatformString())); return instance; } default: break; } } trackUncommittedFiles(rootDir, externalResourceHelper) { // if git is not available, set default value of uncommitted changes to undefined this.executionDetails.uncommittedChanges = undefined; const containsUncommittedChanges = externalResourceHelper.trackUncommittedFiles(rootDir, this.globalIndex); if (containsUncommittedChanges === null) { // git is not available return; } this.executionDetails.uncommittedChanges = containsUncommittedChanges; } insertCPUProfile(rootDir, profile, externalResourceHelper, metricsDataCollection) { return __awaiter(this, void 0, void 0, function* () { const stateMachine = new InsertCPUProfileStateMachine_1.InsertCPUProfileStateMachine(this); const resolveFunctionIdentifierHelper = new ResolveFunctionIdentifierHelper_1.ResolveFunctionIdentifierHelper(rootDir, externalResourceHelper); yield stateMachine.insertCPUProfile(rootDir, resolveFunctionIdentifierHelper, profile, metricsDataCollection); }); } storeToFile(filePath, kind, config) { super.storeToFileReport(filePath, kind, types_1.ReportType.ProjectReport, config); } toBuffer() { const buffers = [ constants_1.BIN_FILE_MAGIC, BufferHelper_1.BufferHelper.String2LToBuffer(this.reportVersion), BufferHelper_1.BufferHelper.String2LToBuffer(JSON.stringify(this.executionDetails)), BufferHelper_1.BufferHelper.String2LToBuffer(JSON.stringify(this.projectMetaData)), BufferHelper_1.BufferHelper.String4LToBuffer(JSON.stringify(this.globalIndex)), super.toBuffer(types_1.ReportType.ProjectReport) ]; return Buffer.concat(buffers); } shouldBeStoredInRegistry() { return __awaiter(this, void 0, void 0, function* () { // every accumulated report should be stored in the registry // and every report that was not created in the jest environment should be stored in the registry return (this.executionDetails.origin !== types_1.ProjectReportOrigin.jestEnv || this.kind === types_1.ReportKind.accumulated); }); } static versionFromBinFile(filePath) { if (!fs.existsSync(filePath.toPlatformString())) { return undefined; } return ProjectReport.versionFromBuffer(fs.readFileSync(filePath.toPlatformString())); } static versionFromBuffer(buffer) { let remainingBuffer = buffer; if (buffer.byteLength < 2) { throw new Error('ProjectReport.consumeFromBuffer: not enough bytes remaining'); } const magic = buffer.subarray(0, constants_1.BIN_FILE_MAGIC.length); if (magic.compare(constants_1.BIN_FILE_MAGIC) !== 0) { throw new Error(`ProjectReport.consumeFromBuffer: not a binary ${constants_1.REPORT_FILE_EXTENSION} format`); } remainingBuffer = buffer.subarray(constants_1.BIN_FILE_MAGIC.length); const { instance: reportVersion, remainingBuffer: newRemainingBuffer0 } = BufferHelper_1.BufferHelper.String2LFromBuffer(remainingBuffer); remainingBuffer = newRemainingBuffer0; return reportVersion; } static consumeFromBuffer(buffer, // eslint-disable-next-line @typescript-eslint/no-unused-vars config) { let remainingBuffer = buffer; if (buffer.byteLength < 2) { throw new Error('ProjectReport.consumeFromBuffer: not enough bytes remaining'); } const magic = buffer.subarray(0, constants_1.BIN_FILE_MAGIC.length); if (magic.compare(constants_1.BIN_FILE_MAGIC) !== 0) { throw new Error(`ProjectReport.consumeFromBuffer: not a binary ${constants_1.REPORT_FILE_EXTENSION} format`); } remainingBuffer = buffer.subarray(constants_1.BIN_FILE_MAGIC.length); const { // eslint-disable-next-line @typescript-eslint/no-unused-vars instance: reportVersion, remainingBuffer: newRemainingBuffer0 } = BufferHelper_1.BufferHelper.String2LFromBuffer(remainingBuffer); remainingBuffer = newRemainingBuffer0; const { instance: executionDetails_JSON_string, remainingBuffer: newRemainingBuffer1 } = BufferHelper_1.BufferHelper.String2LFromBuffer(remainingBuffer); remainingBuffer = newRemainingBuffer1; const executionDetails = JSON.parse(executionDetails_JSON_string); const { instance: projectMetaData_JSON_string, remainingBuffer: newRemainingBuffer2 } = BufferHelper_1.BufferHelper.String2LFromBuffer(remainingBuffer); remainingBuffer = newRemainingBuffer2; const projectMetaData = JSON.parse(projectMetaData_JSON_string); const { instance: globalIndex_JSON_string, remainingBuffer: newRemainingBuffer3 } = BufferHelper_1.BufferHelper.String4LFromBuffer(remainingBuffer); remainingBuffer = newRemainingBuffer3; const globalIndex = GlobalIndex_1.GlobalIndex.fromJSON(globalIndex_JSON_string, new NodeModule_1.NodeModule(executionDetails.languageInformation.name, executionDetails.languageInformation.version)); const { instance: report, type: reportType, remainingBuffer: newRemainingBuffer4 } = Report_1.Report.consumeFromBufferReport(remainingBuffer, globalIndex.getModuleIndex('get')); remainingBuffer = newRemainingBuffer4; const result = Object.assign(new ProjectReport(executionDetails, report.kind, projectMetaData, globalIndex, null), report); return { instance: result, type: reportType, remainingBuffer }; } hash() { return Crypto_1.Crypto.hash(this.toBuffer()); } static hashFromBinFile(filePath) { if (!fs.existsSync(filePath.toPlatformString())) { return undefined; } return Crypto_1.Crypto.hash(fs.readFileSync(filePath.toPlatformString())); } } exports.ProjectReport = ProjectReport; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUHJvamVjdFJlcG9ydC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9tb2RlbC9Qcm9qZWN0UmVwb3J0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLHVDQUF3QjtBQUV4Qiw2Q0FBeUM7QUFDekMscURBQWlEO0FBQ2pELHFDQUFpQztBQUNqQywyREFBdUQ7QUFFdkQsdURBQW1EO0FBRW5ELHVEQUFtRDtBQUduRCw0Q0FBOEU7QUFFOUUsNkNBQXlDO0FBQ3pDLHlEQUFxRDtBQUVyRCwrRkFBMkY7QUFDM0YsZ0hBQTRHO0FBQzVHLFFBQVE7QUFDUixvQ0FPaUI7QUFFakIsTUFBYSxhQUFjLFNBQVEsZUFBTTtJQU94QyxZQUNDLGdCQUFnRCxFQUNoRCxJQUFnQixFQUNoQixlQUFrQyxFQUNsQyxXQUF5QixFQUN6QixNQUE4QjtRQUU5QixJQUFJLEtBQUssR0FBRyxXQUFXLENBQUE7UUFDdkIsSUFBSSxLQUFLLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDekIsS0FBSyxHQUFHLElBQUkseUJBQVcsQ0FDdEIsSUFBSSx1QkFBVSxDQUNiLGdCQUFnQixDQUFDLG1CQUFtQixDQUFDLElBQUksRUFDekMsZ0JBQWdCLENBQUMsbUJBQW1CLENBQUMsT0FBTyxDQUM1QyxDQUNELENBQUE7UUFDRixDQUFDO1FBQ0QsS0FBSyxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUE7UUFDM0MsSUFBSSxDQUFDLFdBQVcsR0FBRyxLQUFLLENBQUE7UUFFeEIsTUFBTSxVQUFVLEdBQ2YsTUFBTSxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQywrQkFBYyxDQUFDLFdBQVcsRUFBRSxDQUFBO1FBRTdELElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxnQkFBZ0IsQ0FBQTtRQUV4QyxJQUFJLGVB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