@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
JavaScript
;
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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