diff options
author | RabsRincon <ruben@rinconblanco.es> | 2022-09-12 09:13:35 +0200 |
---|---|---|
committer | RabsRincon <ruben@rinconblanco.es> | 2022-09-12 09:13:35 +0200 |
commit | 2a310b31867069dc4915d1a45124f0d4c8eb0bc2 (patch) | |
tree | 9bbd94d9de590f313c7d71918a974731f3acb932 | |
parent | 8000ee89124a0c1c94a686cd8f7898b054679193 (diff) | |
download | compiler-explorer-gh-4189.tar.gz compiler-explorer-gh-4189.zip |
Properly tsfy base-toolsgh-4189
-rw-r--r-- | lib/base-compiler.ts | 3 | ||||
-rwxr-xr-x | lib/options-handler.js | 31 | ||||
-rwxr-xr-x | lib/tooling/base-tool.interface.ts | 49 | ||||
-rwxr-xr-x | lib/tooling/base-tool.ts | 80 | ||||
-rw-r--r-- | lib/tooling/compiler-dropin-tool.js | 4 | ||||
-rw-r--r-- | lib/tooling/llvm-cov-tool.ts | 36 | ||||
-rw-r--r-- | lib/utils.ts | 9 | ||||
-rw-r--r-- | test/options-handler.js | 2 | ||||
-rw-r--r-- | types/compilation/compilation.interfaces.ts | 5 |
9 files changed, 137 insertions, 82 deletions
diff --git a/lib/base-compiler.ts b/lib/base-compiler.ts index 3f78031e2..ac9efd3a8 100644 --- a/lib/base-compiler.ts +++ b/lib/base-compiler.ts @@ -72,6 +72,7 @@ import {IAsmParser} from './parsers/asm-parser.interfaces'; import {LlvmPassDumpParser} from './parsers/llvm-pass-dump-parser'; import {getToolchainPath} from './toolchain-utils'; import * as utils from './utils'; +import {ToolTypeKey} from './tooling/base-tool.interface'; export class BaseCompiler { public compiler: any; @@ -1300,7 +1301,7 @@ export class BaseCompiler { return this.postProcess(asmResult, outputFilename, filters); } - runToolsOfType(tools, type, compilationInfo): Promise<ToolResult>[] { + runToolsOfType(tools, type: ToolTypeKey, compilationInfo): Promise<ToolResult>[] { const tooling: Promise<ToolResult>[] = []; if (tools) { for (const tool of tools) { diff --git a/lib/options-handler.js b/lib/options-handler.js index 953817c4f..21e754bec 100755 --- a/lib/options-handler.js +++ b/lib/options-handler.js @@ -31,7 +31,7 @@ import _ from 'underscore'; import {logger} from './logger'; import {getToolTypeByKey} from './tooling'; -import {asSafeVer, getHash, splitArguments} from './utils'; +import {asSafeVer, getHash, splitArguments, splitIntoArray} from './utils'; /*** * Handles the setup of the options object passed on each page request @@ -143,7 +143,7 @@ export class ClientOptionsHandler { name: this.compilerProps(lang, toolBaseName + '.name'), type: this.compilerProps(lang, toolBaseName + '.type'), exe: toolPath, - exclude: this.compilerProps(lang, toolBaseName + '.exclude'), + exclude: splitIntoArray(this.compilerProps(lang, toolBaseName + '.exclude')), includeKey: this.compilerProps(lang, toolBaseName + '.includeKey'), options: splitArguments(this.compilerProps(lang, toolBaseName + '.options')), args: this.compilerProps(lang, toolBaseName + '.args'), @@ -168,14 +168,6 @@ export class ClientOptionsHandler { return tools; } - splitIntoArray(value, defaultArr) { - if (value) { - return value.split(':'); - } else { - return defaultArr; - } - } - parseLibraries(baseLibs) { const libraries = {}; for (const [lang, forLang] of Object.entries(baseLibs)) { @@ -187,14 +179,11 @@ export class ClientOptionsHandler { name: this.compilerProps(lang, libBaseName + '.name'), url: this.compilerProps(lang, libBaseName + '.url'), description: this.compilerProps(lang, libBaseName + '.description'), - staticliblink: this.splitIntoArray( - this.compilerProps(lang, libBaseName + '.staticliblink'), - [], - ), - liblink: this.splitIntoArray(this.compilerProps(lang, libBaseName + '.liblink'), []), - dependencies: this.splitIntoArray(this.compilerProps(lang, libBaseName + '.dependencies'), []), + staticliblink: splitIntoArray(this.compilerProps(lang, libBaseName + '.staticliblink')), + liblink: splitIntoArray(this.compilerProps(lang, libBaseName + '.liblink')), + dependencies: splitIntoArray(this.compilerProps(lang, libBaseName + '.dependencies')), versions: {}, - examples: this.splitIntoArray(this.compilerProps(lang, libBaseName + '.examples'), []), + examples: splitIntoArray(this.compilerProps(lang, libBaseName + '.examples')), options: splitArguments(this.compilerProps(lang, libBaseName + '.options', '')), }; const listedVersions = `${this.compilerProps(lang, libBaseName + '.versions')}`; @@ -203,18 +192,18 @@ export class ClientOptionsHandler { const libVersionName = libBaseName + `.versions.${version}`; const versionObject = { version: this.compilerProps(lang, libVersionName + '.version'), - staticliblink: this.splitIntoArray( + staticliblink: splitIntoArray( this.compilerProps(lang, libVersionName + '.staticliblink'), libraries[lang][lib].staticliblink, ), - alias: this.splitIntoArray(this.compilerProps(lang, libVersionName + '.alias'), []), - dependencies: this.splitIntoArray( + alias: splitIntoArray(this.compilerProps(lang, libVersionName + '.alias')), + dependencies: splitIntoArray( this.compilerProps(lang, libVersionName + '.dependencies'), libraries[lang][lib].dependencies, ), path: [], libpath: [], - liblink: this.splitIntoArray( + liblink: splitIntoArray( this.compilerProps(lang, libVersionName + '.liblink'), libraries[lang][lib].liblink, ), diff --git a/lib/tooling/base-tool.interface.ts b/lib/tooling/base-tool.interface.ts new file mode 100755 index 000000000..afc092d21 --- /dev/null +++ b/lib/tooling/base-tool.interface.ts @@ -0,0 +1,49 @@ +// Copyright (c) 2022, Compiler Explorer Authors +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import {LanguageKey} from '../../types/languages.interfaces'; + +export type ToolTypeKey = 'independent' | 'postcompilation'; + +export type ToolInfo = { + id: string; + name?: string; + type?: ToolTypeKey; + exe: string; + exclude: string[]; + includeKey?: string; + options: string[]; + args?: string; + languageId?: LanguageKey; + stdinHint?: string; + monacoStdin?: string; + icon?: string; + darkIcon?: string; + compilerLanguage: LanguageKey; +}; + +export type ToolEnv = { + ceProps: (key: string, defaultValue?: any) => string | boolean | number | undefined; + compilerProps: (key: string, defaultValue?: any) => string | boolean | number | undefined; +}; diff --git a/lib/tooling/base-tool.ts b/lib/tooling/base-tool.ts index dac1a6f5f..aae1449f6 100755 --- a/lib/tooling/base-tool.ts +++ b/lib/tooling/base-tool.ts @@ -27,11 +27,15 @@ import path from 'path'; import PromClient from 'prom-client'; import _ from 'underscore'; +import {ExecutionOptions, ToolResult} from '../../types/compilation/compilation.interfaces'; +import {ResultLine} from '../../types/resultline/resultline.interfaces'; import * as exec from '../exec'; import {logger} from '../logger'; -import * as utils from '../utils'; -import {ToolEnv, ToolInfo} from './base-tool.interface'; -import {ExecutionOptions} from '../../types/compilation/compilation.interfaces'; +import {parseOutput} from '../utils'; + +import {ToolEnv, ToolInfo, ToolTypeKey} from './base-tool.interface'; +import {UnprocessedExecResult} from '../../types/execution/execution.interfaces'; +import {Library, SelectedLibraryVersion} from '../../types/libraries/libraries.interfaces'; const toolCounter = new PromClient.Counter({ name: 'tool_invocations_total', @@ -39,29 +43,22 @@ const toolCounter = new PromClient.Counter({ labelNames: ['language', 'name'], }); -type BaseToolInfo = Omit<ToolInfo, 'exclude'> & {exclude?: string}; - export class BaseTool { protected tool: ToolInfo; private env: ToolEnv; private addOptionsToToolArgs = true; - protected parseOutput: (...args: any[]) => any; - constructor(toolInfo: BaseToolInfo, env: ToolEnv) { - this.tool = { - ...toolInfo, - exclude: toolInfo.exclude ? toolInfo.exclude.split(':') : [], - }; + constructor(toolInfo: ToolInfo, env: ToolEnv) { + this.tool = toolInfo; this.env = env; this.addOptionsToToolArgs = true; - this.parseOutput = utils.parseOutput; } getId() { return this.tool.id; } - getType() { + getType(): ToolTypeKey { return this.tool.type || 'independent'; } @@ -71,7 +68,7 @@ export class BaseTool { return this.tool.id.replace(/[^\da-z]/gi, '_') + timestamp_str + '_'; } - isCompilerExcluded(compilerId: string, compilerProps: ToolEnv['compilerProps']) { + isCompilerExcluded(compilerId: string, compilerProps: ToolEnv['compilerProps']): boolean { if (this.tool.includeKey) { // If the includeKey is set, we only support compilers that have a truthy 'includeKey'. if (!compilerProps(this.tool.includeKey)) { @@ -79,7 +76,7 @@ export class BaseTool { } // Even if the include key is truthy, we fall back to the exclusion list. } - return this.tool.exclude.find(excl => compilerId.includes(excl)); + return this.tool.exclude.find(excl => compilerId.includes(excl)) !== undefined; } exec(toolExe: string, args: string[], options: ExecutionOptions) { @@ -94,19 +91,24 @@ export class BaseTool { }; } - createErrorResponse(message: string) { + // By default calls utils.parseOutput, but lets subclasses override their output processing + protected parseOutput(lines: string, inputFilename?: string, pathPrefix?: string): ResultLine[] { + return parseOutput(lines, inputFilename, pathPrefix); + } + + createErrorResponse(message: string): ToolResult { return { id: this.tool.id, name: this.tool.name, code: -1, languageId: 'stderr', stdout: [], - stderr: utils.parseOutput(message), + stderr: this.parseOutput(message), }; } // mostly copy&paste from base-compiler.js - findLibVersion(selectedLib, supportedLibraries) { + findLibVersion(selectedLib: SelectedLibraryVersion, supportedLibraries: Record<string, Library>) { const foundLib = _.find(supportedLibraries, (o, libId) => libId === selectedLib.id); if (!foundLib) return false; @@ -114,38 +116,40 @@ export class BaseTool { } // mostly copy&paste from base-compiler.js - getIncludeArguments(libraries, supportedLibraries) { + getIncludeArguments(libraries: SelectedLibraryVersion[], supportedLibraries: Record<string, Library>): string[] { const includeFlag = '-I'; - return _.flatten( - _.map(libraries, selectedLib => { - const foundVersion = this.findLibVersion(selectedLib, supportedLibraries); - if (!foundVersion) return false; + return libraries.flatMap(selectedLib => { + const foundVersion = this.findLibVersion(selectedLib, supportedLibraries); + if (!foundVersion) return []; - return _.map(foundVersion.path, path => includeFlag + path); - }), - ); + return foundVersion.path.map(path => includeFlag + path); + }); } - getLibraryOptions(libraries, supportedLibraries) { - return _.flatten( - _.map(libraries, selectedLib => { - const foundVersion = this.findLibVersion(selectedLib, supportedLibraries); - if (!foundVersion) return false; + getLibraryOptions(libraries: SelectedLibraryVersion[], supportedLibraries: Record<string, Library>): string[] { + return libraries.flatMap(selectedLib => { + const foundVersion = this.findLibVersion(selectedLib, supportedLibraries); + if (!foundVersion) return []; - return foundVersion.options; - }), - ); + return foundVersion.options; + }); } - async runTool(compilationInfo, inputFilepath, args, stdin /*, supportedLibraries*/) { + async runTool( + compilationInfo: Record<any, any>, + inputFilepath?: string, + args?: string[], + stdin?: string, + supportedLibraries?: Record<string, Library>, + ) { if (this.tool.name) { toolCounter.inc({ language: compilationInfo.compiler.lang, name: this.tool.name, }); } - const execOptions = this.getDefaultExecOptions() as ExecutionOptions; + const execOptions = this.getDefaultExecOptions(); if (inputFilepath) execOptions.customCwd = path.dirname(inputFilepath); execOptions.input = stdin; @@ -164,8 +168,8 @@ export class BaseTool { } } - convertResult(result, inputFilepath, exeDir) { - const transformedFilepath = result.filenameTransform(inputFilepath); + convertResult(result: UnprocessedExecResult, inputFilepath?: string, exeDir?: string): ToolResult { + const transformedFilepath = inputFilepath ? result.filenameTransform(inputFilepath) : undefined; return { id: this.tool.id, name: this.tool.name, diff --git a/lib/tooling/compiler-dropin-tool.js b/lib/tooling/compiler-dropin-tool.js index ab7be7c33..31a52b1a1 100644 --- a/lib/tooling/compiler-dropin-tool.js +++ b/lib/tooling/compiler-dropin-tool.js @@ -101,8 +101,8 @@ export class CompilerDropinTool extends BaseTool { async runTool(compilationInfo, inputFilepath, args, stdin, supportedLibraries) { const sourcefile = inputFilepath; - const includeflags = super.getIncludeArguments(compilationInfo.libraries, supportedLibraries); - const libOptions = super.getLibraryOptions(compilationInfo.libraries, supportedLibraries); + const includeflags = this.getIncludeArguments(compilationInfo.libraries, supportedLibraries); + const libOptions = this.getLibraryOptions(compilationInfo.libraries, supportedLibraries); const compileFlags = this.getOrderedArguments(compilationInfo, includeflags, libOptions, args, sourcefile); if (!compileFlags) { diff --git a/lib/tooling/llvm-cov-tool.ts b/lib/tooling/llvm-cov-tool.ts index 0fd24e356..adf12ffe5 100644 --- a/lib/tooling/llvm-cov-tool.ts +++ b/lib/tooling/llvm-cov-tool.ts @@ -22,26 +22,34 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. -import fs from 'fs-extra'; import path from 'path'; -import {logger} from '../logger'; -import {BaseTool} from './base-tool'; import {ExecutionOptions} from '../../types/compilation/compilation.interfaces'; +import {BaseTool} from './base-tool'; + export class LLVMCovTool extends BaseTool { static get key() { return 'llvm-cov-tool'; } - override async runTool(compilationInfo, inputFilepath, args, stdin /*, supportedLibraries*/) { - const compilationExecOptions = this.getDefaultExecOptions() as ExecutionOptions; + override async runTool(compilationInfo, inputFilepath, args, stdin) { + const compilationExecOptions = this.getDefaultExecOptions(); compilationExecOptions.customCwd = path.dirname(inputFilepath); compilationExecOptions.input = stdin; try { + const generatedExecutableName = this.getUniqueFilePrefix() + '-coverage.a'; const compilationResult = await this.exec( compilationInfo.compiler.exe, - ['-fprofile-instr-generate', '-fcoverage-mapping', '-g', '-O0', inputFilepath, '-o', 'coverage.a'], + [ + '-fprofile-instr-generate', + '-fcoverage-mapping', + '-g', + '-O0', + inputFilepath, + '-o', + generatedExecutableName, + ], compilationExecOptions, ); @@ -54,7 +62,7 @@ export class LLVMCovTool extends BaseTool { const runExecOptions = this.getDefaultExecOptions() as ExecutionOptions; runExecOptions.customCwd = path.dirname(inputFilepath); - await this.exec('./coverage.a', [], { + await this.exec('./' + generatedExecutableName, [], { ...runExecOptions, input: stdin, }); @@ -62,9 +70,10 @@ export class LLVMCovTool extends BaseTool { const folder = path.dirname(this.tool.exe); const profdataPath = path.join(folder, 'llvm-profdata'); + const generatedProfdataName = this.getUniqueFilePrefix() + '.profdata'; const profdataResult = await this.exec( profdataPath, - ['merge', '-sparse', './default.profraw', '-o', './coverage.profdata'], + ['merge', '-sparse', './default.profraw', '-o', './' + generatedProfdataName], runExecOptions, ); if (profdataResult.code !== 0) { @@ -73,20 +82,15 @@ export class LLVMCovTool extends BaseTool { ); } - const cppFiltPath = path.join(folder, 'llvm-cxxfilt'); const covResult = await this.exec( this.tool.exe, [ 'show', - './coverage.a', - '-instr-profile=./coverage.profdata', + './' + generatedExecutableName, + '-instr-profile=./' + generatedProfdataName, '-format', 'text', '-use-color', - '-Xdemangler', - cppFiltPath, - '-Xdemangler', - '-n', '-compilation-dir=./', ...args, ], @@ -98,7 +102,7 @@ export class LLVMCovTool extends BaseTool { return this.createErrorResponse(`<llvm-cov error>\n${covResult.stdout}\n${covResult.stderr}`); } } catch (e) { - return this.createErrorResponse(`<Tool error: ${e}`); + return this.createErrorResponse(`<Tool error: ${e}>`); } } } diff --git a/lib/utils.ts b/lib/utils.ts index 840c9cb79..dc3087528 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -367,6 +367,15 @@ export function base32Encode(buffer: Buffer): string { return output; } +// Splits a : separated list into its own array, or to default if input is undefined +export function splitIntoArray(input?: string, defaultArray: string[] = []): string[] { + if (input !== undefined) { + return input.split(':'); + } else { + return defaultArray; + } +} + export function splitArguments(options = ''): string[] { // escape hashes first, otherwise they're interpreted as comments const escapedOptions = options.replaceAll(/#/g, '\\#'); diff --git a/test/options-handler.js b/test/options-handler.js index 80ab8c80a..fd8253ced 100644 --- a/test/options-handler.js +++ b/test/options-handler.js @@ -511,7 +511,6 @@ describe('Options handler', () => { fake: { faketool: { addOptionsToToolArgs: true, - parseOutput: parseOutput, tool: { args: undefined, compilerLanguage: 'fake', @@ -531,7 +530,6 @@ describe('Options handler', () => { }, someothertool: { addOptionsToToolArgs: true, - parseOutput: parseOutput, tool: { args: undefined, compilerLanguage: 'fake', diff --git a/types/compilation/compilation.interfaces.ts b/types/compilation/compilation.interfaces.ts index 3f1703b0f..6d686ace5 100644 --- a/types/compilation/compilation.interfaces.ts +++ b/types/compilation/compilation.interfaces.ts @@ -23,6 +23,7 @@ // POSSIBILITY OF SUCH DAMAGE. import {BuildEnvDownloadInfo} from '../../lib/buildenvsetup/buildenv.interfaces'; +import {LanguageKey} from '../languages.interfaces'; import {ResultLine} from '../resultline/resultline.interfaces'; export type CompilationResult = { @@ -114,9 +115,9 @@ export type Artifact = { export type ToolResult = { id: string; - name: string; + name?: string; code: number; - languageId: string; + languageId?: LanguageKey | 'stderr'; stderr: ResultLine[]; stdout: ResultLine[]; artifact?: Artifact; |