@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
291 lines • 27.6 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 (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__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());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProjectReport = void 0;
const fs = __importStar(require("fs"));
const axios_1 = __importDefault(require("axios"));
const form_data_1 = __importDefault(require("form-data"));
const NodeModule_1 = require("./NodeModule");
const ProfilerConfig_1 = require("./ProfilerConfig");
const Report_1 = require("./Report");
const SystemInformation_1 = require("./SystemInformation");
const GlobalIndex_1 = require("./index/GlobalIndex");
const GitHelper_1 = require("../helper/GitHelper");
const UnifiedPath_1 = require("../system/UnifiedPath");
const Crypto_1 = require("../system/Crypto");
const BufferHelper_1 = require("../helper/BufferHelper");
const AuthenticationHelper_1 = require("../helper/AuthenticationHelper");
const InsertCPUProfileHelper_1 = require("../helper/InsertCPUProfileHelper");
const app_1 = require("../constants/app");
// 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()
};
}
}
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 systemInformationList = args.map((x) => x.executionDetails.systemInformation);
if (!SystemInformation_1.SystemInformation.sameSystem(...systemInformationList)) {
throw new Error('ProjectReport.merge: cannot merge ProjectReports from different systems');
}
const executionDetails = args[0].executionDetails;
for (const currentProjectReport of args) {
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, ...args));
result.globalIndex = moduleIndex.globalIndex;
return result;
}
toJSON() {
if (process.env.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) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
// if git is not available, set default value of uncommitted changes to undefined
this.executionDetails.uncommittedChanges = undefined;
const uncommittedFiles = GitHelper_1.GitHelper.uncommittedFiles();
if (uncommittedFiles === undefined) {
return;
}
// git is available, set default value of uncommitted changes to false
this.executionDetails.uncommittedChanges = false;
for (const uncommittedFile of uncommittedFiles) {
const pureRelativeOriginalSourcePath = rootDir.pathTo(new UnifiedPath_1.UnifiedPath(uncommittedFile));
const pathIndex = (_a = this.globalIndex.getModuleIndex('get')) === null || _a === void 0 ? void 0 : _a.getFilePathIndex('get', pureRelativeOriginalSourcePath.toString());
if (pathIndex === undefined) {
continue;
}
pathIndex.containsUncommittedChanges = true;
// if one file has uncommitted changes, the whole project has uncommitted changes
this.executionDetails.uncommittedChanges = true;
}
});
}
insertCPUProfile(rootDir, profile, transformerAdapter, metricsDataCollection) {
return __awaiter(this, void 0, void 0, function* () {
yield InsertCPUProfileHelper_1.InsertCPUProfileHelper.insertCPUProfile(this, rootDir, profile, transformerAdapter, metricsDataCollection);
});
}
storeToFile(filePath, kind, config) {
super.storeToFileReport(filePath, kind, types_1.ReportType.ProjectReport, config);
}
toBuffer() {
const buffers = [
app_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, app_1.BIN_FILE_MAGIC.length);
if (magic.compare(app_1.BIN_FILE_MAGIC) !== 0) {
throw new Error('ProjectReport.consumeFromBuffer: not a binary .oak format');
}
remainingBuffer = buffer.subarray(app_1.BIN_FILE_MAGIC.length);
const { instance: reportVersion, remainingBuffer: newRemainingBuffer0 } = BufferHelper_1.BufferHelper.String2LFromBuffer(remainingBuffer);
remainingBuffer = newRemainingBuffer0;
return reportVersion;
}
static consumeFromBuffer(buffer, config) {
let remainingBuffer = buffer;
if (buffer.byteLength < 2) {
throw new Error('ProjectReport.consumeFromBuffer: not enough bytes remaining');
}
const magic = buffer.subarray(0, app_1.BIN_FILE_MAGIC.length);
if (magic.compare(app_1.BIN_FILE_MAGIC) !== 0) {
throw new Error('ProjectReport.consumeFromBuffer: not a binary .oak format');
}
remainingBuffer = buffer.subarray(app_1.BIN_FILE_MAGIC.length);
const { 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()));
}
uploadToRegistry(config) {
return __awaiter(this, void 0, void 0, function* () {
const usedConfig = config !== undefined ? config : ProfilerConfig_1.ProfilerConfig.autoResolve();
if (!usedConfig.uploadEnabled()) {
return;
}
const compressedBuffer = yield BufferHelper_1.BufferHelper.compressBuffer(this.toBuffer());
const formData = new form_data_1.default();
formData.append('file', compressedBuffer, 'filename.txt');
formData.append('auth', AuthenticationHelper_1.AuthenticationHelper.getAuthentication());
try {
const result = yield axios_1.default.post(usedConfig.getRegistryUploadUrl(), formData, {
timeout: 5000, // Set a timeout of 5 seconds
headers: {
'Content-Type': 'multipart/form-data'
}
});
return result;
}
catch (_a) { }
});
}
}
exports.ProjectReport = ProjectReport;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUHJvamVjdFJlcG9ydC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9tb2RlbC9Qcm9qZWN0UmVwb3J0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsdUNBQXdCO0FBRXhCLGtEQUF5QjtBQUN6QiwwREFBZ0M7QUFFaEMsNkNBQXlDO0FBQ3pDLHFEQUFpRDtBQUNqRCxxQ0FBaUM7QUFDakMsMkRBQXVEO0FBRXZELHFEQUFpRDtBQUlqRCxtREFBK0M7QUFFL0MsdURBQW1EO0FBQ25ELDZDQUF5QztBQUN6Qyx5REFBcUQ7QUFDckQseUVBQXFFO0FBQ3JFLDZFQUF5RTtBQUN6RSwwQ0FBaUQ7QUFDakQsUUFBUTtBQUNSLG9DQU9pQjtBQUVqQixNQUFhLGFBQWMsU0FBUSxlQUFNO0lBS3hDLFlBQ0MsZ0JBQWdELEVBQ2hELElBQWdCLEVBQ2hCLGVBQWtDLEVBQ2xDLFdBQXlCLEVBQ3pCLE1BQThCO1FBRTlCLElBQUksS0FBSyxHQUFHLFdBQVcsQ0FBQTtRQUN2QixJQUFJLEtBQUssS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUN6QixLQUFLLEdBQUcsSUFBSSx5QkFBVyxDQUFDLElBQUksdUJBQVUsQ0FDckMsZ0JBQWdCLENBQUMsbUJBQW1CLENBQUMsSUFBSSxFQUN6QyxnQkFBZ0IsQ0FBQyxtQkFBbUIsQ0FBQyxPQUFPLENBQzVDLENBQUMsQ0FBQTtRQUNILENBQUM7UUFDRCxLQUFLLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQTtRQUMzQyxJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQTtRQUV4QixNQUFNLFVBQVUsR0FBRyxNQUFNLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLCtCQUFjLENBQUMsV0FBVyxFQUFFLENBQUE7UUFFL0UsSUFBSSxDQUFDLGdCQUFn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