UNPKG

4.47 kBPlain TextView Raw
1import * as fs from 'fs-extra';
2import { join, resolve } from 'path';
3import { IConfig } from '@oclif/config';
4import { getConfig, TBBaseCommand } from '../command-config';
5import createConsumeableHTML, {
6 ITracerBenchTraceResult,
7} from '../helpers/create-consumable-html';
8import { tbResultsFolder, config } from '../helpers/flags';
9import printToPDF from '../helpers/print-to-pdf';
10import { chalkScheme } from '../helpers/utils';
11
12const ARTIFACT_FILE_NAME = 'artifact';
13
14export interface IReportFlags {
15 tbResultsFolder: string;
16 config?: string;
17}
18
19export 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 // instantiated before this.run()
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 * Ensure the input file is valid and call the helper function "createConsumeableHTML"
43 * to generate the HTML string for the output file.
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 // If the input file cannot be found, exit with an error
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