1 | import * as fs from 'fs-extra';
|
2 | import { join, resolve } from 'path';
|
3 | import { IConfig } from '@oclif/config';
|
4 | import { getConfig, TBBaseCommand } from '../command-config';
|
5 | import createConsumeableHTML, {
|
6 | ITracerBenchTraceResult,
|
7 | } from '../helpers/create-consumable-html';
|
8 | import { tbResultsFolder, config } from '../helpers/flags';
|
9 | import printToPDF from '../helpers/print-to-pdf';
|
10 | import { chalkScheme } from '../helpers/utils';
|
11 |
|
12 | const ARTIFACT_FILE_NAME = 'artifact';
|
13 |
|
14 | export interface IReportFlags {
|
15 | tbResultsFolder: string;
|
16 | config?: string;
|
17 | }
|
18 |
|
19 | export default class Report extends TBBaseCommand {
|
20 | public static description = `Parses the output json from tracerbench and formats it into pdf and html`;
|
21 | public static flags = {
|
22 | tbResultsFolder: tbResultsFolder({ required: true }),
|
23 | config: config(),
|
24 | };
|
25 | public reportFlags: IReportFlags;
|
26 |
|
27 | constructor(argv: string[], config: IConfig) {
|
28 | super(argv, config);
|
29 | const { flags } = this.parse(Report);
|
30 |
|
31 | this.reportFlags = flags;
|
32 | }
|
33 |
|
34 | public async init() {
|
35 | const { flags } = this.parse(Report);
|
36 | this.parsedConfig = getConfig(flags.config, flags, this.explicitFlags);
|
37 |
|
38 | this.reportFlags = flags;
|
39 | await this.parseFlags();
|
40 | }
|
41 | |
42 |
|
43 |
|
44 |
|
45 | public async run() {
|
46 | const tbResultsFolder = this.reportFlags.tbResultsFolder;
|
47 | const inputFilePath = join(tbResultsFolder, 'compare.json');
|
48 | let absPathToHTML;
|
49 | let absOutputPath;
|
50 | let renderedHTML;
|
51 | let htmlOutputPath;
|
52 | let outputFileName;
|
53 | let inputData: ITracerBenchTraceResult[] = [];
|
54 |
|
55 | if (!fs.existsSync(inputFilePath)) {
|
56 | this.error(
|
57 | `Input json file does not exist. Please make sure ${inputFilePath} exists`,
|
58 | { exit: 1 }
|
59 | );
|
60 | }
|
61 |
|
62 | try {
|
63 | inputData = JSON.parse(fs.readFileSync(inputFilePath, 'utf8'));
|
64 | } catch (error) {
|
65 | this.error(
|
66 | `Had issues parsing the input JSON file. Please make sure ${inputFilePath} is a valid JSON`,
|
67 | { exit: 1 }
|
68 | );
|
69 | }
|
70 |
|
71 | const controlData = inputData.find(element => {
|
72 | return element.set === 'control';
|
73 | }) as ITracerBenchTraceResult;
|
74 |
|
75 | const experimentData = inputData.find(element => {
|
76 | return element.set === 'experiment';
|
77 | }) as ITracerBenchTraceResult;
|
78 |
|
79 | if (!controlData || !experimentData) {
|
80 | this.error(`Missing control or experiment set in JSON`, { exit: 1 });
|
81 | }
|
82 |
|
83 | outputFileName = this.determineOutputFileName(tbResultsFolder);
|
84 | renderedHTML = createConsumeableHTML(
|
85 | controlData,
|
86 | experimentData,
|
87 | this.parsedConfig
|
88 | );
|
89 | if (!fs.existsSync(tbResultsFolder)) {
|
90 | fs.mkdirSync(tbResultsFolder, { recursive: true });
|
91 | }
|
92 |
|
93 | htmlOutputPath = join(tbResultsFolder, `/${outputFileName}.html`);
|
94 | absPathToHTML = resolve(htmlOutputPath);
|
95 |
|
96 | fs.writeFileSync(absPathToHTML, renderedHTML);
|
97 |
|
98 | absOutputPath = resolve(join(tbResultsFolder + `/${outputFileName}.pdf`));
|
99 |
|
100 | await printToPDF(`file://${absPathToHTML}`, absOutputPath);
|
101 | this.log(
|
102 | `\n${chalkScheme.blackBgBlue(
|
103 | ` ${chalkScheme.white('Benchmark Reports')} `
|
104 | )}`
|
105 | );
|
106 | this.log(
|
107 | `\nJSON: ${chalkScheme.tbBranding.blue.underline.bold(
|
108 | `${this.parsedConfig.tbResultsFolder}/compare.json`
|
109 | )}`
|
110 | );
|
111 | this.log(
|
112 | `\nPDF: ${chalkScheme.tbBranding.blue.underline.bold(absPathToHTML)}`
|
113 | );
|
114 | this.log(
|
115 | `\nHTML: ${chalkScheme.tbBranding.blue.underline.bold(absOutputPath)}\n`
|
116 | );
|
117 | }
|
118 | private async parseFlags() {
|
119 | const { tbResultsFolder } = (this.parsedConfig as unknown) as IReportFlags;
|
120 |
|
121 | // if the folder for the tracerbench results file
|
122 | // does not exist then create it
|
123 | if (!fs.existsSync(tbResultsFolder)) {
|
124 | fs.mkdirSync(tbResultsFolder);
|
125 | }
|
126 | }
|
127 | private determineOutputFileName(outputFolder: string): string {
|
128 | let count = 1;
|
129 | while (true) {
|
130 | const candidateHTML = join(
|
131 | outputFolder,
|
132 | `${ARTIFACT_FILE_NAME}-${count}.html`
|
133 | );
|
134 | const candidatePDF = join(
|
135 | outputFolder,
|
136 | `${ARTIFACT_FILE_NAME}-${count}.pdf`
|
137 | );
|
138 | if (!fs.existsSync(candidateHTML) && !fs.existsSync(candidatePDF)) {
|
139 | break;
|
140 | }
|
141 | count += 1;
|
142 | }
|
143 | return `artifact-${count}`;
|
144 | }
|
145 | }
|
146 |
|
\ | No newline at end of file |