Remote execution (#6700)

This commit is contained in:
Patrick Quist
2024-10-26 17:42:22 +02:00
committed by GitHub
parent 648795d0f5
commit 4fe8397fac
45 changed files with 2121 additions and 136 deletions

26
app.ts
View File

@@ -53,6 +53,9 @@ import {CompilationEnvironment} from './lib/compilation-env.js';
import {CompilationQueue} from './lib/compilation-queue.js';
import {CompilerFinder} from './lib/compiler-finder.js';
import {startWineInit} from './lib/exec.js';
import {RemoteExecutionQuery} from './lib/execution/execution-query.js';
import {initHostSpecialties} from './lib/execution/execution-triple.js';
import {startExecutionWorkerThread} from './lib/execution/sqs-execution-queue.js';
import {CompileHandler} from './lib/handlers/compile.js';
import * as healthCheck from './lib/handlers/health-check.js';
import {NoScriptHandler} from './lib/handlers/noscript.js';
@@ -522,9 +525,16 @@ async function main() {
startWineInit();
RemoteExecutionQuery.initRemoteExecutionArchs(ceProps, defArgs.env);
const clientOptionsHandler = new ClientOptionsHandler(sources, compilerProps, defArgs);
const compilationQueue = CompilationQueue.fromProps(compilerProps.ceProps);
const compilationEnvironment = new CompilationEnvironment(compilerProps, compilationQueue, defArgs.doCache);
const compilationEnvironment = new CompilationEnvironment(
compilerProps,
awsProps,
compilationQueue,
defArgs.doCache,
);
const compileHandler = new CompileHandler(compilationEnvironment, awsProps);
const storageType = getStorageTypeByKey(storageSolution);
const storageHandler = new storageType(httpRoot, compilerProps, awsProps);
@@ -538,6 +548,8 @@ async function main() {
let initialCompilers: CompilerInfo[];
let prevCompilers;
const isExecutionWorker = ceProps<boolean>('execqueue.is_worker', false);
if (opts.prediscovered) {
const prediscoveredCompilersJson = await fs.readFile(opts.prediscovered, 'utf8');
initialCompilers = JSON.parse(prediscoveredCompilersJson);
@@ -548,7 +560,7 @@ async function main() {
} else {
const initialFindResults = await compilerFinder.find();
initialCompilers = initialFindResults.compilers;
if (initialCompilers.length === 0) {
if (!isExecutionWorker && initialCompilers.length === 0) {
throw new Error('Unexpected failure, no compilers found!');
}
if (defArgs.ensureNoCompilerClash) {
@@ -653,7 +665,8 @@ async function main() {
// Handle healthchecks at the root, as they're not expected from the outside world
.use(
'/healthcheck',
new healthCheck.HealthCheckHandler(compilationQueue, healthCheckFilePath, compileHandler).handle,
new healthCheck.HealthCheckHandler(compilationQueue, healthCheckFilePath, compileHandler, isExecutionWorker)
.handle,
)
.use(httpRoot, router)
.use((req, res, next) => {
@@ -847,6 +860,13 @@ async function main() {
logger.info(' with disabled caching');
}
setupEventLoopLagLogging();
if (isExecutionWorker) {
await initHostSpecialties();
startExecutionWorkerThread(ceProps, awsProps, compilationEnvironment);
}
startListening(webServer);
}

View File

@@ -0,0 +1,9 @@
httpRoot=/aarch64prod
restrictToLanguages=none
heaptrackPath=/opt/compiler-explorer/heaptrack-aarch64-v1.3.0
libSegFaultPath=/opt/compiler-explorer/glibc-tools-arm64
execqueue.queue_url=https://sqs.us-east-1.amazonaws.com/052730242331/prod-execqueue
execqueue.events_url=wss://events.compiler-explorer.com/prod
execqueue.is_worker=true

View File

@@ -0,0 +1,9 @@
httpRoot=/aarch64staging
restrictToLanguages=none
heaptrackPath=/opt/compiler-explorer/heaptrack-aarch64-v1.3.0
libSegFaultPath=/opt/compiler-explorer/glibc-tools-arm64
execqueue.queue_url=https://sqs.us-east-1.amazonaws.com/052730242331/staging-execqueue
execqueue.events_url=wss://events.compiler-explorer.com/staging
execqueue.is_worker=true

View File

@@ -76,3 +76,8 @@ compilationStatsNotifier=S3(compiler-explorer-logs,compile-stats,us-east-1,15m)
compilationStaleAfterMs=60000
compilerVersionsUrl=https://api.compiler-explorer.com/get_deployed_exe_version
execqueue.remote_archs_url=https://api.compiler-explorer.com/get_remote_execution_archs
execqueue.queue_url=https://sqs.us-east-1.amazonaws.com/052730242331/prod-execqueue
execqueue.events_url=wss://events.compiler-explorer.com/prod
execqueue.is_worker=false

View File

@@ -44,3 +44,7 @@ formatter.clangformat.styles=Google:LLVM:Mozilla:Chromium:WebKit:Microsoft:GNU
formatter.clangformat.type=clangformat
compilationStatsNotifier=S3(compiler-explorer-logs,compile-stats,us-east-1,15m)
execqueue.queue_url=https://sqs.us-east-1.amazonaws.com/052730242331/prod-execqueue
execqueue.events_url=wss://events.compiler-explorer.com/prod
execqueue.is_worker=false

View File

@@ -2,3 +2,6 @@ extraBodyClass=staging
httpRoot=/staging
motdUrl=/motd/motd-staging.json
sentryEnvironment=staging
execqueue.queue_url=https://sqs.us-east-1.amazonaws.com/052730242331/staging-execqueue
execqueue.events_url=wss://events.compiler-explorer.com/staging

View File

@@ -0,0 +1,5 @@
sandboxType=nsjail
executionType=nsjail
wine=
wineServer=
firejail=/usr/local/firejail-0.9.70/bin/firejail

View File

@@ -1,6 +1,7 @@
compilers=&rust:&rustgcc:&mrustc:&rustccggcc
objdumper=/opt/compiler-explorer/gcc-14.1.0/bin/objdump
linker=/opt/compiler-explorer/gcc-14.1.0/bin/gcc
aarch64linker=/opt/compiler-explorer/arm64/gcc-14.1.0/aarch64-unknown-linux-gnu/bin/aarch64-unknown-linux-gnu-gcc
defaultCompiler=r1820
demangler=/opt/compiler-explorer/gcc-14.1.0/bin/c++filt
demanglerArgs=--format=rust

View File

@@ -96,8 +96,12 @@ import {
import {BaseDemangler, getDemanglerTypeByKey} from './demangler/index.js';
import {LLVMIRDemangler} from './demangler/llvm.js';
import * as exec from './exec.js';
import {BaseExecutionTriple} from './execution/base-execution-triple.js';
import {IExecutionEnvironment} from './execution/execution-env.interfaces.js';
import {RemoteExecutionQuery} from './execution/execution-query.js';
import {matchesCurrentHost} from './execution/execution-triple.js';
import {getExecutionEnvironmentByKey} from './execution/index.js';
import {RemoteExecutionEnvironment} from './execution/remote-execution-env.js';
import {ExternalParserBase} from './external-parsers/base.js';
import {getExternalParserByKey} from './external-parsers/index.js';
import {ParsedRequest} from './handlers/compile.js';
@@ -124,6 +128,7 @@ import {
getSysrootByToolchainPath,
getToolchainFlagFromOptions,
getToolchainPath,
getToolchainPathWithOptionsArr,
hasSysrootArg,
hasToolchainArg,
removeToolchainArg,
@@ -988,7 +993,7 @@ export class BaseCompiler implements ICompiler {
);
}
getSharedLibraryPathsAsLdLibraryPathsForExecution(libraries: SelectedLibraryVersion[], dirPath: string): string[] {
getSharedLibraryPathsAsLdLibraryPathsForExecution(key: CacheKey, dirPath: string): string[] {
let paths = '';
if (!this.alwaysResetLdPath) {
paths = process.env.LD_LIBRARY_PATH || '';
@@ -996,11 +1001,28 @@ export class BaseCompiler implements ICompiler {
return _.union(
paths.split(path.delimiter).filter(p => !!p),
this.compiler.ldPath,
this.getExtraLdPaths(key),
this.compiler.libPath,
this.getSharedLibraryPaths(libraries, dirPath),
this.getSharedLibraryPaths(key.libraries, dirPath),
);
}
getExtraLdPaths(key: CacheKey): string[] {
let toolchainPath: any;
if (key.options) {
toolchainPath = getToolchainPathWithOptionsArr(this.compiler.exe, key.options) || this.toolchainPath;
}
if (toolchainPath) {
const sysrootPath = getSysrootByToolchainPath(toolchainPath);
if (sysrootPath) {
return [path.join(sysrootPath, 'lib')];
}
}
return [];
}
getIncludeArguments(libraries: SelectedLibraryVersion[], dirPath: string): string[] {
const includeFlag = this.compiler.includeFlag || '-I';
return libraries.flatMap(selectedLib => {
@@ -1608,7 +1630,7 @@ export class BaseCompiler implements ICompiler {
return utils.changeExtension(inputFilename, '.ll');
}
getOutputFilename(dirPath: string, outputFilebase: string, key?: CacheKey): string {
getOutputFilename(dirPath: string, outputFilebase: string, key?: any): string {
let filename;
if (key && key.backendOptions && key.backendOptions.customOutputFilename) {
filename = key.backendOptions.customOutputFilename;
@@ -1623,7 +1645,7 @@ export class BaseCompiler implements ICompiler {
}
}
getExecutableFilename(dirPath: string, outputFilebase: string, key?: CacheKey) {
getExecutableFilename(dirPath: string, outputFilebase: string, key?: CacheKey | CompilationCacheKey) {
return this.getOutputFilename(dirPath, outputFilebase, key);
}
@@ -1888,44 +1910,45 @@ export class BaseCompiler implements ICompiler {
return buildResult;
}
async getOrBuildExecutable(key: CacheKey, bypassCache: BypassCache) {
async getOrBuildExecutable(
key: CacheKey,
bypassCache: BypassCache,
executablePackageHash: string,
): Promise<BuildResult> {
const dirPath = await this.newTempDir();
if (!bypassCompilationCache(bypassCache)) {
const buildResults = await this.loadPackageWithExecutable(key, dirPath);
if (buildResults) return buildResults;
const buildResult = await this.loadPackageWithExecutable(key, executablePackageHash, dirPath);
if (buildResult) return buildResult;
}
let compilationResult: BuildResult;
let buildResult: BuildResult;
try {
compilationResult = await this.buildExecutableInFolder(key, dirPath);
if (compilationResult.code !== 0) {
return compilationResult;
buildResult = await this.buildExecutableInFolder(key, dirPath);
if (buildResult.code !== 0) {
return buildResult;
}
} catch (e) {
return this.handleUserError(e, dirPath);
return this.handleUserBuildError(e, dirPath);
}
compilationResult.preparedLdPaths = _.union(
this.compiler.ldPath,
this.getSharedLibraryPathsAsLdLibraryPathsForExecution(key.libraries, dirPath),
);
compilationResult.defaultExecOptions = this.getDefaultExecOptions();
buildResult.preparedLdPaths = this.getSharedLibraryPathsAsLdLibraryPathsForExecution(key, dirPath);
buildResult.defaultExecOptions = this.getDefaultExecOptions();
await this.storePackageWithExecutable(key, dirPath, compilationResult);
await this.storePackageWithExecutable(executablePackageHash, dirPath, buildResult);
if (!compilationResult.dirPath) {
compilationResult.dirPath = dirPath;
if (!buildResult.dirPath) {
buildResult.dirPath = dirPath;
}
return compilationResult;
return buildResult;
}
async loadPackageWithExecutable(key: CacheKey, dirPath: string) {
async loadPackageWithExecutable(key: CacheKey, executablePackageHash: string, dirPath: string) {
const compilationResultFilename = 'compilation-result.json';
try {
const startTime = process.hrtime.bigint();
const outputFilename = await this.env.executableGet(key, dirPath);
const outputFilename = await this.env.executableGet(executablePackageHash, dirPath);
if (outputFilename) {
logger.debug(`Using cached package ${outputFilename}`);
await this.packager.unpack(outputFilename, dirPath);
@@ -1953,16 +1976,25 @@ export class BaseCompiler implements ICompiler {
return false;
}
async storePackageWithExecutable(key: CacheKey, dirPath: string, compilationResult: CompilationResult) {
async storePackageWithExecutable(
executablePackageHash: string,
dirPath: string,
compilationResult: CompilationResult,
): Promise<void> {
const compilationResultFilename = 'compilation-result.json';
const packDir = await this.newTempDir();
const packagedFile = path.join(packDir, 'package.tgz');
try {
await fs.writeFile(path.join(dirPath, compilationResultFilename), JSON.stringify(compilationResult));
// first remove tmpdir from executableFilename, this path will never be the same
// (it's kept in the original compilationResult to keep Tools from breaking that want the full path)
// note: couldn't use structuredClone() here, not sure why not
const clonedResult = JSON.parse(JSON.stringify(compilationResult));
clonedResult.executableFilename = utils.maskRootdir(clonedResult.executableFilename);
await fs.writeFile(path.join(dirPath, compilationResultFilename), JSON.stringify(clonedResult));
await this.packager.package(dirPath, packagedFile);
const hash = await this.env.executablePut(key, packagedFile);
logger.debug('Storing ' + hash);
await this.env.executablePut(executablePackageHash, packagedFile);
} catch (err) {
logger.error('Caught an error trying to put to cache: ', {err});
} finally {
@@ -1974,6 +2006,15 @@ export class BaseCompiler implements ICompiler {
return utils.processExecutionResult(input, inputFilename);
}
async runExecutableRemotely(
executablePackageHash: string,
executeOptions: ExecutableExecutionOptions,
execTriple: BaseExecutionTriple,
): Promise<BasicExecutionResult> {
const env = new RemoteExecutionEnvironment(this.env, execTriple, executablePackageHash);
return await env.execute(executeOptions);
}
async runExecutable(
executable: string,
executeParameters: ExecutableExecutionOptions,
@@ -2038,7 +2079,10 @@ export class BaseCompiler implements ICompiler {
if (this.compiler.interpreted) {
return this.handleInterpreting(key, executeParameters);
}
const buildResult = await this.getOrBuildExecutable(key, bypassCache);
const executablePackageHash = this.env.getExecutableHash(key);
const buildResult = await this.getOrBuildExecutable(key, bypassCache, executablePackageHash);
if (buildResult.code !== 0) {
return {
code: -1,
@@ -2065,27 +2109,42 @@ export class BaseCompiler implements ICompiler {
return verboseResult;
}
if (!this.compiler.supportsExecute) {
return {
code: -1,
didExecute: false,
buildResult,
stderr: [{text: 'Compiler does not support execution'}],
stdout: [],
timedOut: false,
};
}
if (buildResult.preparedLdPaths) {
executeParameters.ldPath = buildResult.preparedLdPaths;
} else {
executeParameters.ldPath = this.getSharedLibraryPathsAsLdLibraryPathsForExecution(
key.libraries,
buildResult.dirPath,
key,
buildResult.dirPath || '',
);
}
const result = await this.runExecutable(buildResult.executableFilename, executeParameters, buildResult.dirPath);
const execTriple = await RemoteExecutionQuery.guessExecutionTripleForBuildresult(buildResult);
if (!matchesCurrentHost(execTriple)) {
if (await RemoteExecutionQuery.isPossible(execTriple)) {
const result = await this.runExecutableRemotely(executablePackageHash, executeParameters, execTriple);
return moveArtifactsIntoResult(buildResult, {
...result,
didExecute: true,
buildResult: buildResult,
});
} else {
return {
code: -1,
didExecute: false,
buildResult,
stderr: [{text: `No execution available for ${execTriple.toString()}`}],
stdout: [],
execTime: '',
timedOut: false,
};
}
}
const result = await this.runExecutable(
buildResult.executableFilename,
executeParameters,
unwrap<string>(buildResult.dirPath),
);
return moveArtifactsIntoResult(buildResult, {
...result,
didExecute: true,
@@ -2431,6 +2490,21 @@ export class BaseCompiler implements ICompiler {
};
}
handleUserBuildError(error, dirPath): BuildResult {
return {
dirPath,
okToCache: false,
code: -1,
timedOut: false,
asm: [{text: `<${error.message}>`}],
stdout: [],
stderr: [{text: `<${error.message}>`}],
downloads: [],
executableFilename: '',
compilationOptions: [],
};
}
async doBuildstepAndAddToResult(
result: CompilationResult,
name: string,
@@ -2515,7 +2589,11 @@ export class BaseCompiler implements ICompiler {
}
}
async cmake(files: FiledataPair[], key: ParsedRequest, bypassCache: BypassCache): Promise<CompilationResult> {
async cmake(
files: FiledataPair[],
parsedRequest: ParsedRequest,
bypassCache: BypassCache,
): Promise<CompilationResult> {
// key = {source, options, backendOptions, filters, bypassCache, tools, executeParameters, libraries};
if (!this.compiler.supportsBinary) {
@@ -2531,33 +2609,35 @@ export class BaseCompiler implements ICompiler {
return errorResult;
}
_.defaults(key.filters, this.getDefaultFilters());
key.filters.binary = true;
key.filters.dontMaskFilenames = true;
_.defaults(parsedRequest.filters, this.getDefaultFilters());
parsedRequest.filters.binary = true;
parsedRequest.filters.dontMaskFilenames = true;
const libsAndOptions = this.createLibsAndOptions(key);
const libsAndOptions = this.createLibsAndOptions(parsedRequest);
const toolchainPath = this.getDefaultOrOverridenToolchainPath(key.backendOptions.overrides || []);
const toolchainPath = this.getDefaultOrOverridenToolchainPath(parsedRequest.backendOptions.overrides || []);
const dirPath = await this.newTempDir();
const doExecute = key.filters.execute;
const doExecute = parsedRequest.filters.execute;
// todo: executeOptions.env should be set??
const executeOptions: ExecutableExecutionOptions = {
args: (key.executeParameters.args as string[]) || [],
stdin: key.executeParameters.stdin || '',
ldPath: this.getSharedLibraryPathsAsLdLibraryPaths(key.libraries, dirPath),
runtimeTools: key.executeParameters?.runtimeTools || [],
args: parsedRequest.executeParameters.args || [],
stdin: parsedRequest.executeParameters.stdin || '',
ldPath: this.getSharedLibraryPathsAsLdLibraryPaths(parsedRequest.libraries, dirPath),
runtimeTools: parsedRequest.executeParameters?.runtimeTools || [],
env: {},
};
const cacheKey = this.getCmakeCacheKey(key, files);
const cacheKey = this.getCmakeCacheKey(parsedRequest, files);
const executablePackageHash = this.env.getExecutableHash(cacheKey);
const outputFilename = this.getExecutableFilename(path.join(dirPath, 'build'), this.outputFilebase, cacheKey);
let fullResult: CompilationResult = bypassExecutionCache(bypassCache)
? null
: await this.loadPackageWithExecutable(cacheKey, dirPath);
: await this.loadPackageWithExecutable(cacheKey, executablePackageHash, dirPath);
if (fullResult) {
fullResult.retreivedFromCache = true;
@@ -2591,12 +2671,15 @@ export class BaseCompiler implements ICompiler {
fullResult.downloads = await this.setupBuildEnvironment(cacheKey, dirPath, true);
const toolchainparam = this.getCMakeExtToolchainParam(key.backendOptions.overrides || []);
const toolchainparam = this.getCMakeExtToolchainParam(parsedRequest.backendOptions.overrides || []);
const cmakeArgs = utils.splitArguments(key.backendOptions.cmakeArgs);
const partArgs: string[] = [toolchainparam, ...this.getExtraCMakeArgs(key), ...cmakeArgs, '..'].filter(
Boolean,
); // filter out empty args
const cmakeArgs = utils.splitArguments(parsedRequest.backendOptions.cmakeArgs);
const partArgs: string[] = [
toolchainparam,
...this.getExtraCMakeArgs(parsedRequest),
...cmakeArgs,
'..',
].filter(Boolean); // filter out empty args
const useNinja = this.env.ceProps('useninja');
const fullArgs: string[] = useNinja ? ['-GNinja'].concat(partArgs) : partArgs;
@@ -2656,7 +2739,7 @@ export class BaseCompiler implements ICompiler {
compilationOptions: this.getUsedEnvironmentVariableFlags(makeExecParams),
};
if (!key.backendOptions.skipAsm) {
if (!parsedRequest.backendOptions.skipAsm) {
const [asmResult] = await this.checkOutputFileAndDoPostProcess(
fullResult.result,
outputFilename,
@@ -2672,14 +2755,43 @@ export class BaseCompiler implements ICompiler {
});
}
await this.storePackageWithExecutable(cacheKey, dirPath, fullResult);
await this.storePackageWithExecutable(executablePackageHash, dirPath, fullResult);
}
if (fullResult.result) fullResult.result.dirPath = dirPath;
if (fullResult.result) {
fullResult.result.dirPath = dirPath;
if (this.compiler.supportsExecute && doExecute) {
fullResult.execResult = await this.runExecutable(outputFilename, executeOptions, dirPath);
fullResult.didExecute = true;
if (doExecute && fullResult.result.code === 0) {
const execTriple = await RemoteExecutionQuery.guessExecutionTripleForBuildresult({
...fullResult,
downloads: fullResult.downloads || [],
executableFilename: outputFilename,
compilationOptions: fullResult.compilationOptions || [],
});
if (matchesCurrentHost(execTriple)) {
fullResult.execResult = await this.runExecutable(outputFilename, executeOptions, dirPath);
fullResult.didExecute = true;
} else {
if (await RemoteExecutionQuery.isPossible(execTriple)) {
fullResult.execResult = await this.runExecutableRemotely(
executablePackageHash,
executeOptions,
execTriple,
);
fullResult.didExecute = true;
} else {
fullResult.execResult = {
code: -1,
okToCache: false,
stdout: [],
stderr: [{text: `No execution available for ${execTriple.toString()}`}],
execTime: '',
timedOut: false,
};
}
}
}
}
const optOutput = undefined;
@@ -2689,7 +2801,7 @@ export class BaseCompiler implements ICompiler {
false,
cacheKey,
executeOptions,
key.tools,
parsedRequest.tools,
cacheKey.backendOptions,
cacheKey.filters,
libsAndOptions.options,

View File

@@ -0,0 +1,128 @@
// Copyright (c) 2024, 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 {InstructionSet} from '../../types/instructionsets.js';
import {executeDirect} from '../exec.js';
import {logger} from '../logger.js';
export enum OSType {
linux = 'linux',
windows = 'win32',
}
export type BinaryInfo = {
instructionSet: InstructionSet;
os: OSType;
};
export class BinaryInfoLinux {
static getInstructionSetForArchText(value: string): InstructionSet {
switch (value) {
case 'x86-64': {
return 'amd64';
}
case 'intel 80386': {
return 'x86';
}
case '80386': {
return 'x86';
}
case 'arm aarch64': {
return 'aarch64';
}
case 'aarch64': {
return 'aarch64';
}
case 'arm': {
return 'arm32';
}
case 'atmel avr 8-bit': {
return 'avr';
}
case 'ucb risc-v': {
return 'riscv64';
}
case '64-bit powerpc or cisco 7500': {
return 'powerpc';
}
case 'powerpc or cisco 4500': {
return 'powerpc';
}
case 'mips': {
return 'mips';
}
case 'loongarch': {
return 'loongarch';
}
default: {
logger.error(`Unknown architecture text: ${value}`);
return 'amd64';
}
}
}
static removeComments(value: string): string {
let filtered: string = '';
let inComment: boolean = false;
for (const c of value) {
if (!inComment && c === '(') {
inComment = true;
} else if (inComment && c === ')') {
inComment = false;
} else if (!inComment) {
filtered += c;
}
}
return filtered.trim();
}
static parseFileInfo(output: string): BinaryInfo | undefined {
const csv: string[] = output.split(', ').map(val => val.trim().toLowerCase());
const isElf = csv[0].startsWith('elf');
const isPE = csv[0].startsWith('pe32');
if (isElf) {
return {
os: OSType.linux,
instructionSet: this.getInstructionSetForArchText(csv[1]),
};
} else if (isPE) {
const filteredLine = this.removeComments(csv[0]);
const lastWordPos = filteredLine.lastIndexOf(' ');
const lastWord = filteredLine.substring(lastWordPos + 1);
return {
os: OSType.windows,
instructionSet: this.getInstructionSetForArchText(lastWord),
};
}
return undefined;
}
static async readFile(filepath: string): Promise<BinaryInfo | undefined> {
const info = await executeDirect('/usr/bin/file', ['-b', filepath], {});
if (info.code === 0) return this.parseFileInfo(info.stdout);
return undefined;
}
}

View File

@@ -26,11 +26,10 @@ import path from 'path';
import * as fs from 'fs-extra';
import {ExecutionOptionsWithEnv} from '../types/compilation/compilation.interfaces.js';
import {BaseCompiler} from './base-compiler.js';
import {logger} from './logger.js';
import * as utils from './utils.js';
import {ExecutionOptionsWithEnv} from '../../types/compilation/compilation.interfaces.js';
import {BaseCompiler} from '../base-compiler.js';
import {logger} from '../logger.js';
import * as utils from '../utils.js';
export class WinUtils {
protected re_dll_name = /dll name: (.*\.dll)/i;

View File

@@ -38,13 +38,12 @@ import {CompilationQueue, EnqueueOptions, Job} from './compilation-queue.js';
import {FormattingHandler} from './handlers/formatting.js';
import {logger} from './logger.js';
import type {PropertyGetter} from './properties.interfaces.js';
import {CompilerProps} from './properties.js';
import {CompilerProps, PropFunc} from './properties.js';
import {createStatsNoter, IStatsNoter} from './stats.js';
type PropFunc = (s: string, a?: any) => any;
export class CompilationEnvironment {
ceProps: PropertyGetter;
awsProps: PropFunc;
compilationQueue: CompilationQueue | undefined;
compilerProps: PropFunc;
okOptions: RegExp;
@@ -60,8 +59,14 @@ export class CompilationEnvironment {
statsNoter: IStatsNoter;
private logCompilerCacheAccesses: boolean;
constructor(compilerProps: CompilerProps, compilationQueue: CompilationQueue | undefined, doCache?: boolean) {
constructor(
compilerProps: CompilerProps,
awsProps: PropFunc,
compilationQueue: CompilationQueue | undefined,
doCache?: boolean,
) {
this.ceProps = compilerProps.ceProps;
this.awsProps = awsProps;
this.compilationQueue = compilationQueue;
this.compilerProps = compilerProps.get.bind(compilerProps);
// So people running local instances don't break suddenly when updating
@@ -158,8 +163,11 @@ export class CompilationEnvironment {
return this.compilerCache.put(key, JSON.stringify(result), creator);
}
async executableGet(object: CacheableValue, destinationFolder: string): Promise<string | null> {
const key = BaseCache.hash(object) + '_exec';
getExecutableHash(object: CacheableValue): string {
return BaseCache.hash(object) + '_exec';
}
async executableGet(key: string, destinationFolder: string): Promise<string | null> {
const result = await this.executableCache.get(key);
if (!result.hit) return null;
const filepath = destinationFolder + '/' + key;
@@ -167,10 +175,8 @@ export class CompilationEnvironment {
return filepath;
}
async executablePut(object: CacheableValue, filepath: string): Promise<string> {
const key = BaseCache.hash(object) + '_exec';
async executablePut(key: string, filepath: string): Promise<void> {
await this.executableCache.put(key, fs.readFileSync(filepath));
return key;
}
enqueue<T>(job: Job<T>, options?: EnqueueOptions) {

View File

@@ -29,6 +29,7 @@ import {BypassCache, CacheKey, ExecutionOptions} from '../../types/compilation/c
import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
import {ExecutableExecutionOptions} from '../../types/execution/execution.interfaces.js';
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
import {assert} from '../assert.js';
import {BaseCompiler} from '../base-compiler.js';
import {CompilationEnvironment} from '../compilation-env.js';
import {logger} from '../logger.js';
@@ -89,7 +90,9 @@ export class CerberusCompiler extends BaseCompiler {
}
override async handleInterpreting(key: CacheKey, executeParameters: ExecutableExecutionOptions) {
const compileResult = await this.getOrBuildExecutable(key, BypassCache.None);
const executionPackageHash = this.env.getExecutableHash(key);
const compileResult = await this.getOrBuildExecutable(key, BypassCache.None, executionPackageHash);
assert(compileResult.dirPath !== undefined);
if (compileResult.code === 0) {
executeParameters.args = [
'--exec',

View File

@@ -32,7 +32,7 @@ import {BypassCache, CacheKey, CompilationResult} from '../../types/compilation/
import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
import {ExecutableExecutionOptions} from '../../types/execution/execution.interfaces.js';
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
import {unwrap} from '../assert.js';
import {assert, unwrap} from '../assert.js';
import {BaseCompiler, SimpleOutputFilenameCompiler} from '../base-compiler.js';
import {CompilationEnvironment} from '../compilation-env.js';
import {logger} from '../logger.js';
@@ -135,12 +135,14 @@ export class JavaCompiler extends BaseCompiler implements SimpleOutputFilenameCo
key: CacheKey,
executeParameters: ExecutableExecutionOptions,
): Promise<CompilationResult> {
const compileResult = await this.getOrBuildExecutable(key, BypassCache.None);
const executionPackageHash = this.env.getExecutableHash(key);
const compileResult = await this.getOrBuildExecutable(key, BypassCache.None, executionPackageHash);
if (compileResult.code === 0) {
const extraXXFlags: string[] = [];
if (Semver.gte(utils.asSafeVer(this.compiler.semver), '11.0.0', true)) {
extraXXFlags.push('-XX:-UseDynamicNumberOfCompilerThreads');
}
assert(compileResult.dirPath !== undefined);
executeParameters.args = [
'-Xss136K', // Reduce thread stack size
'-XX:CICompilerCount=2', // Reduce JIT compilation threads. 2 is minimum

View File

@@ -26,6 +26,7 @@ import {BypassCache, CacheKey, CompilationResult} from '../../types/compilation/
import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
import {ExecutableExecutionOptions} from '../../types/execution/execution.interfaces.js';
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
import {assert} from '../assert.js';
import {SimpleOutputFilenameCompiler} from '../base-compiler.js';
import {CompilationEnvironment} from '../compilation-env.js';
@@ -105,7 +106,9 @@ export class KotlinCompiler extends JavaCompiler implements SimpleOutputFilename
...key,
options: ['-include-runtime', '-d', 'example.jar'],
};
const compileResult = await this.getOrBuildExecutable(alteredKey, BypassCache.None);
const executablePackageHash = this.env.getExecutableHash(key);
const compileResult = await this.getOrBuildExecutable(alteredKey, BypassCache.None, executablePackageHash);
assert(compileResult.dirPath !== undefined);
if (compileResult.code !== 0) {
return {
stdout: compileResult.stdout,

View File

@@ -43,7 +43,8 @@ import {changeExtension, parseRustOutput} from '../utils.js';
import {RustParser} from './argument-parsers.js';
export class RustCompiler extends BaseCompiler {
linker: string;
amd64linker: string;
aarch64linker: string;
static get key() {
return 'rust';
@@ -69,7 +70,8 @@ export class RustCompiler extends BaseCompiler {
moduleScopeArg: ['-C', 'llvm-args=-print-module-scope'],
noDiscardValueNamesArg: isNightly ? ['-Z', 'fewer-names=no'] : [],
};
this.linker = this.compilerProps<string>('linker');
this.amd64linker = this.compilerProps<string>('linker');
this.aarch64linker = this.compilerProps<string>('aarch64linker');
}
override async generateIR(
@@ -207,6 +209,26 @@ export class RustCompiler extends BaseCompiler {
return [options, overrides];
}
override changeOptionsBasedOnOverrides(options: string[], overrides: ConfiguredOverrides): string[] {
const newOptions = super.changeOptionsBasedOnOverrides(options, overrides);
if (this.aarch64linker) {
const useAarch64Linker = !!overrides.find(
override => override.name === CompilerOverrideType.arch && override.value.includes('aarch64'),
);
if (useAarch64Linker) {
for (let idx = 0; idx < newOptions.length; idx++) {
if (newOptions[idx].indexOf('-Clinker=') === 0) {
newOptions[idx] = `-Clinker=${this.aarch64linker}`;
}
}
}
}
return newOptions;
}
override optionsForBackend(backendOptions: Record<string, any>, outputFilename: string) {
// The super class handles the GCC dump files that may be needed by
// rustc-cg-gcc subclass.
@@ -225,8 +247,8 @@ export class RustCompiler extends BaseCompiler {
const userRequestedEmit = _.any(unwrap(userOptions), opt => opt.includes('--emit'));
if (filters.binary) {
options = options.concat(['--crate-type', 'bin']);
if (this.linker) {
options = options.concat(`-Clinker=${this.linker}`);
if (this.amd64linker) {
options = options.concat(`-Clinker=${this.amd64linker}`);
}
} else if (filters.binaryObject) {
options = options.concat(['--crate-type', 'lib']);

View File

@@ -27,7 +27,7 @@ import path from 'path';
import {BuildResult, BypassCache, CacheKey, CompilationResult} from '../../types/compilation/compilation.interfaces.js';
import {ExecutableExecutionOptions} from '../../types/execution/execution.interfaces.js';
import {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
import {copyNeededDlls} from '../win-utils.js';
import {copyNeededDlls} from '../binaries/win-utils.js';
import {ClangCompiler} from './clang.js';

View File

@@ -27,7 +27,7 @@ import path from 'path';
import {BuildResult, BypassCache, CacheKey, CompilationResult} from '../../types/compilation/compilation.interfaces.js';
import {ExecutableExecutionOptions} from '../../types/execution/execution.interfaces.js';
import {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
import {copyNeededDlls} from '../win-utils.js';
import {copyNeededDlls} from '../binaries/win-utils.js';
import {GCCCompiler} from './gcc.js';

View File

@@ -144,8 +144,6 @@ export class LocalExecutionEnvironment implements IExecutionEnvironment {
}
}
// todo: what to do about the rest of the runtimeTools?
if (
this.buildResult &&
this.buildResult.defaultExecOptions &&
@@ -157,12 +155,20 @@ export class LocalExecutionEnvironment implements IExecutionEnvironment {
else env.PATH = this.buildResult.defaultExecOptions.env.PATH;
}
let extraLdPaths: string[] = [];
if (env.LD_LIBRARY_PATH) {
extraLdPaths = env.LD_LIBRARY_PATH.split(path.delimiter);
delete env.LD_LIBRARY_PATH;
}
const execOptions: ExecutionOptionsWithEnv = {
env,
};
if (this.buildResult && this.buildResult.preparedLdPaths) {
execOptions.ldPath = this.buildResult.preparedLdPaths;
execOptions.ldPath = this.buildResult.preparedLdPaths.concat(extraLdPaths);
} else {
execOptions.ldPath = extraLdPaths;
}
return execOptions;
@@ -170,6 +176,7 @@ export class LocalExecutionEnvironment implements IExecutionEnvironment {
async execute(params: ExecutionParams): Promise<BasicExecutionResult> {
assert(this.buildResult);
assert(this.dirPath !== 'not initialized');
const execExecutableOptions: ExecutableExecutionOptions = {
args: typeof params.args === 'string' ? utils.splitArguments(params.args) : params.args || [],
@@ -179,15 +186,13 @@ export class LocalExecutionEnvironment implements IExecutionEnvironment {
runtimeTools: params.runtimeTools,
};
const homeDir = await temp.mkdir({prefix: utils.ce_temp_prefix, dir: os.tmpdir()});
// note: this is for a small transition period only, can be removed after a few days
const file = utils.maskRootdir(this.buildResult.executableFilename);
return await this.execBinary(this.buildResult.executableFilename, execExecutableOptions, homeDir);
return await this.execBinary(file, execExecutableOptions, this.dirPath);
}
protected setEnvironmentVariablesFromRuntime(
configuredTools: ConfiguredRuntimeTools,
execOptions: ExecutionOptions,
) {
static setEnvironmentVariablesFromRuntime(configuredTools: ConfiguredRuntimeTools, execOptions: ExecutionOptions) {
for (const runtime of configuredTools) {
if (runtime.name === RuntimeToolType.env) {
for (const env of runtime.options) {
@@ -264,7 +269,7 @@ export class LocalExecutionEnvironment implements IExecutionEnvironment {
if (!execOptions.env) execOptions.env = {};
if (executeParameters.runtimeTools) {
this.setEnvironmentVariablesFromRuntime(executeParameters.runtimeTools, execOptions);
LocalExecutionEnvironment.setEnvironmentVariablesFromRuntime(executeParameters.runtimeTools, execOptions);
for (const runtime of executeParameters.runtimeTools) {
if (runtime.name === RuntimeToolType.heaptrack) {

View File

@@ -0,0 +1,80 @@
// Copyright (c) 2024, 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 {InstructionSet} from '../../types/instructionsets.js';
import {OSType} from '../binaries/binary-utils.js';
export enum ExecutionSpecialty {
cpu = 'cpu',
nvgpu = 'nvgpu',
amdgpu = 'amdgpu',
}
export class BaseExecutionTriple {
protected _instructionSet: InstructionSet = 'amd64';
protected _os: OSType = OSType.linux;
protected _specialty: ExecutionSpecialty = ExecutionSpecialty.cpu;
get instructionSet(): InstructionSet {
return this._instructionSet;
}
set instructionSet(value: InstructionSet) {
this._instructionSet = value;
}
set os(value: OSType) {
this._os = value;
}
get os(): OSType {
return this._os;
}
set specialty(value: ExecutionSpecialty) {
this._specialty = value;
}
get specialty(): ExecutionSpecialty {
return this._specialty;
}
toString(): string {
return `${this._instructionSet}-${this._os}-${this._specialty}`;
}
parse(triple: string) {
if (triple.includes('-')) {
const reTriple = /(\w*)-(\w*)-(\w*)/;
const match = triple.match(reTriple);
if (match) {
this._instructionSet = match[1] as InstructionSet;
this._os = match[2] as OSType;
this._specialty = match[3] as ExecutionSpecialty;
}
} else {
this._instructionSet = triple as InstructionSet;
}
}
}

View File

@@ -0,0 +1,134 @@
// Copyright (c) 2024, 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 {WebSocket} from 'ws';
import {BasicExecutionResult} from '../../types/execution/execution.interfaces.js';
import {logger} from '../logger.js';
import {PropertyGetter} from '../properties.interfaces.js';
export class EventsWsBase {
protected expectClose: boolean = false;
protected events_url: string;
protected ws: WebSocket | undefined = undefined;
protected got_error: boolean = false;
constructor(props: PropertyGetter) {
this.events_url = props<string>('execqueue.events_url', '');
if (this.events_url === '') throw new Error('execqueue.events_url property required');
}
protected connect() {
if (!this.ws) {
this.ws = new WebSocket(this.events_url);
this.ws.on('error', e => {
this.got_error = true;
logger.error(`Error while trying to communicate with websocket at URL ${this.events_url}`);
logger.error(e);
});
}
}
async close(): Promise<void> {
this.expectClose = true;
if (this.ws) {
this.ws.close();
}
}
}
export class EventsWsSender extends EventsWsBase {
async send(guid: string, result: BasicExecutionResult): Promise<void> {
this.connect();
return new Promise(resolve => {
this.ws.on('open', async () => {
this.ws.send(
JSON.stringify({
guid: guid,
...result,
}),
);
resolve();
});
});
}
}
export class EventsWsWaiter extends EventsWsBase {
private timeout: number;
constructor(props: PropertyGetter) {
super(props);
// binaryExecTimeoutMs + 2500 to allow for some generous network latency between completion and receiving the result
this.timeout = props<number>('binaryExecTimeoutMs', 10000) + 2500;
}
async subscribe(guid: string): Promise<void> {
this.connect();
return new Promise((resolve, reject) => {
const errorCheck = setInterval(() => {
if (this.got_error) {
reject();
}
}, 500);
this.ws.on('open', async () => {
this.ws.send(`subscribe: ${guid}`);
clearInterval(errorCheck);
resolve();
});
});
}
async data(): Promise<BasicExecutionResult> {
let runningTime = 0;
return new Promise((resolve, reject) => {
const t = setInterval(() => {
runningTime = runningTime + 1000;
if (runningTime > this.timeout) {
clearInterval(t);
reject('Remote execution timed out without returning a result');
}
}, 1000);
this.ws.on('message', async message => {
clearInterval(t);
try {
const data = JSON.parse(message.toString());
resolve(data);
} catch (e) {
reject(e);
}
});
this.ws.on('close', () => {
clearInterval(t);
if (!this.expectClose) {
reject('Unable to complete remote execution due to unexpected situation');
}
});
});
}
}

View File

@@ -0,0 +1,95 @@
// Copyright (c) 2024, 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 {BuildResult} from '../../types/compilation/compilation.interfaces.js';
import {BinaryInfoLinux} from '../binaries/binary-utils.js';
import {logger} from '../logger.js';
import {PropertyGetter} from '../properties.interfaces.js';
import {BaseExecutionTriple, ExecutionSpecialty} from './base-execution-triple.js';
async function retrieveAllRemoteExecutionArchs(ceProps: PropertyGetter, envs: string[]): Promise<string[]> {
let url: string = ceProps<string>('execqueue.remote_archs_url', '');
try {
if (!url) return [];
if (envs.find(env => env.includes('staging') || env === 'dev')) url += '?env=staging';
// eslint-disable-next-line n/no-unsupported-features/node-builtins
const response = await fetch(url);
if (response.status !== 200) {
throw new Error(`Status ${response.status} on GET ${url}`);
}
return await response.json();
} catch (e) {
logger.error('Error retrieving remote execution architectures');
logger.error(e);
process.exit(1);
}
}
let _available_remote_execution_archs: Promise<BaseExecutionTriple[]>;
export class RemoteExecutionQuery {
static initRemoteExecutionArchs(ceProps: PropertyGetter, envs: string[]) {
_available_remote_execution_archs = new Promise(resolve => {
retrieveAllRemoteExecutionArchs(ceProps, envs).then(archs => {
const triples: BaseExecutionTriple[] = [];
for (const arch of archs) {
const triple = new BaseExecutionTriple();
triple.parse(arch);
triples.push(triple);
}
resolve(triples);
});
});
}
static async isPossible(triple: BaseExecutionTriple): Promise<boolean> {
const triples = await _available_remote_execution_archs;
return !!triples.find(remote => remote.toString() === triple.toString());
}
static async guessExecutionTripleForBuildresult(result: BuildResult): Promise<BaseExecutionTriple> {
const triple = new BaseExecutionTriple();
if (result.executableFilename) {
const info = await BinaryInfoLinux.readFile(result.executableFilename);
if (info) {
triple.instructionSet = info.instructionSet;
triple.os = info.os;
}
} else {
if (result.instructionSet) triple.instructionSet = result.instructionSet;
}
if (result.devices && Object.keys(result.devices).length > 0) {
triple.specialty = ExecutionSpecialty.nvgpu;
}
return triple;
}
}

View File

@@ -0,0 +1,131 @@
// Copyright (c) 2024, 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 os from 'os';
import {InstructionSet} from '../../types/instructionsets.js';
import {OSType} from '../binaries/binary-utils.js';
import {logger} from '../logger.js';
import * as utils from '../utils.js';
import {BaseExecutionTriple, ExecutionSpecialty} from './base-execution-triple.js';
// import fs from 'fs-extra';
let _host_specialty = ExecutionSpecialty.cpu;
function setHostSpecialty(value: ExecutionSpecialty) {
_host_specialty = value;
}
export async function initHostSpecialties(): Promise<void> {
if (os.platform() !== 'win32') {
const nvidiaGpuExists = await utils.fileExists('/dev/nvidia0');
if (nvidiaGpuExists) {
setHostSpecialty(ExecutionSpecialty.nvgpu);
}
// const cpuInfo = await fs.readFile('/proc/cpuinfo');
// if (cpuInfo.includes('GenuineIntel')) {
// }
}
}
class CurrentHostExecHelper {
static isetCanRunOnCurrentHost(value: InstructionSet): boolean {
// os.arch() Possible values are `'arm'`, `'arm64'`, `'ia32'`, `'loong64'`,`'mips'`, `'mipsel'`, `'ppc'`, `'ppc64'`, `'riscv64'`, `'s390'`, `'s390x'`, and `'x64'`.
const hostArch = os.arch();
if (hostArch === 'arm64' && value === 'aarch64') {
return true;
} else if (hostArch === 'arm' && value === 'arm32') {
return true;
} else if (hostArch === 'x64' && (value === 'amd64' || value === 'x86')) {
return true;
} else if (hostArch === 'ia32' && value === 'x86') {
return true;
}
return false;
}
static osMatchesCurrentHost(value: string): boolean {
// Possible values are `'aix'`, `'darwin'`, `'freebsd'`, `'linux'`, `'openbsd'`, `'sunos'`, and `'win32'`
return value === os.platform();
}
static specialtyMatchesCurrentHost(value: ExecutionSpecialty) {
if (value === _host_specialty) return true;
if (_host_specialty === ExecutionSpecialty.nvgpu && value === ExecutionSpecialty.cpu) return true;
return _host_specialty === ExecutionSpecialty.amdgpu && value === ExecutionSpecialty.cpu;
}
static getInstructionSetByNodeJSArch(value: string): InstructionSet {
switch (value) {
case 'x64': {
return 'amd64';
}
case 'ia32': {
return 'x86';
}
case 'arm64': {
return 'aarch64';
}
case 'arm': {
return 'arm32';
}
default: {
return os.arch() as InstructionSet;
}
}
}
}
// note: returns array of BaseExecutionTriple to prepare for the future of fulfilling multiple execution roles, not actually implemented
export function getExecutionTriplesForCurrentHost(): BaseExecutionTriple[] {
const triple = new BaseExecutionTriple();
triple.instructionSet = CurrentHostExecHelper.getInstructionSetByNodeJSArch(os.arch());
const platform = os.platform() as string;
if ((Object.values(OSType) as string[]).includes(platform)) {
triple.os = platform as OSType;
} else {
logger.warning(`getExecutionTripleForCurrentHost - Unsupported platform ${platform}`);
}
triple.specialty = _host_specialty;
return [triple];
}
export function matchesCurrentHost(triple: BaseExecutionTriple): boolean {
const matchesArch = CurrentHostExecHelper.isetCanRunOnCurrentHost(triple.instructionSet);
const matchesOS = CurrentHostExecHelper.osMatchesCurrentHost(triple.os);
const matchesSpecialty = CurrentHostExecHelper.specialtyMatchesCurrentHost(triple.specialty);
return matchesArch && matchesOS && matchesSpecialty;
}

View File

@@ -0,0 +1,110 @@
// Copyright (c) 2024, 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 crypto from 'crypto';
import {ExecutionParams} from '../../types/compilation/compilation.interfaces.js';
import {BasicExecutionResult, ExecutableExecutionOptions} from '../../types/execution/execution.interfaces.js';
import {CompilationEnvironment} from '../compilation-env.js';
import {logger} from '../logger.js';
import {BaseExecutionTriple} from './base-execution-triple.js';
import {EventsWsWaiter} from './events-websocket.js';
import {IExecutionEnvironment} from './execution-env.interfaces.js';
import {SqsExecuteRequester} from './sqs-execution-queue.js';
export class RemoteExecutionEnvironment implements IExecutionEnvironment {
private packageHash: string;
private triple: BaseExecutionTriple;
private execQueue: SqsExecuteRequester;
private guid: string;
private environment: CompilationEnvironment;
constructor(environment: CompilationEnvironment, triple: BaseExecutionTriple, executablePackageHash: string) {
this.environment = environment;
this.triple = triple;
this.guid = crypto.randomUUID();
this.packageHash = executablePackageHash;
this.execQueue = new SqsExecuteRequester(environment.ceProps, environment.awsProps);
logger.info(
`RemoteExecutionEnvironment with ${triple.toString()} and ${executablePackageHash} - guid ${this.guid}`,
);
}
async downloadExecutablePackage(hash: string): Promise<void> {
throw new Error('Method not implemented.');
}
private async queueRemoteExecution(params: ExecutionParams) {
await this.execQueue.push(this.triple, {
guid: this.guid,
hash: this.packageHash,
params: params,
});
}
async execute(params: ExecutionParams): Promise<BasicExecutionResult> {
const startTime = process.hrtime.bigint();
const waiter = new EventsWsWaiter(this.environment.ceProps);
try {
await waiter.subscribe(this.guid);
await this.queueRemoteExecution(params);
const result = await waiter.data();
await waiter.close();
const endTime = process.hrtime.bigint();
// change time to include overhead like SQS, WS, network etc
result.processExecutionResultTime =
parseInt((endTime - startTime).toString()) / 1000000 - parseInt(result.execTime);
return result;
} catch (e) {
waiter.close();
return {
code: -1,
stdout: [],
stderr: [{text: 'Internal error while trying to remotely execute'}],
timedOut: false,
execTime: '',
okToCache: false,
filenameTransform: f => f,
};
}
}
async execBinary(
executable: string,
executeParameters: ExecutableExecutionOptions,
homeDir: string,
extraConfiguration?: any,
): Promise<BasicExecutionResult> {
throw new Error('Method not implemented.');
}
}

View File

@@ -0,0 +1,185 @@
// Copyright (c) 2024, 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 {SQS} from '@aws-sdk/client-sqs';
import {ExecutionParams} from '../../types/compilation/compilation.interfaces.js';
import {BasicExecutionResult} from '../../types/execution/execution.interfaces.js';
import {logger} from '../logger.js';
import {PropertyGetter} from '../properties.interfaces.js';
import {getHash} from '../utils.js';
import {LocalExecutionEnvironment} from './_all.js';
import {BaseExecutionTriple} from './base-execution-triple.js';
import {EventsWsSender} from './events-websocket.js';
import {getExecutionTriplesForCurrentHost} from './execution-triple.js';
export type RemoteExecutionMessage = {
guid: string;
hash: string;
params: ExecutionParams;
};
export class SqsExecuteQueueBase {
protected sqs: SQS;
protected queue_url: string;
constructor(props: PropertyGetter, awsProps: PropertyGetter) {
const region = awsProps<string>('region', '');
this.sqs = new SQS({region: region});
this.queue_url = props<string>('execqueue.queue_url', '');
if (this.queue_url === '') throw new Error('execqueue.queue_url property required');
}
getSqsQueueUrl(triple: BaseExecutionTriple) {
return this.queue_url + '-' + triple.toString() + '.fifo';
}
}
export class SqsExecuteRequester extends SqsExecuteQueueBase {
private async sendMsg(url: string, body: string) {
try {
return await this.sqs.sendMessage({
QueueUrl: url,
MessageBody: body,
MessageGroupId: 'default',
MessageDeduplicationId: getHash(body),
});
} catch (e) {
logger.error(`Error sending message to queue with URL: ${url}`);
throw e;
}
}
async push(triple: BaseExecutionTriple, message: RemoteExecutionMessage): Promise<any> {
const body = JSON.stringify(message);
const url = this.getSqsQueueUrl(triple);
return this.sendMsg(url, body);
}
}
export class SqsWorkerMode extends SqsExecuteQueueBase {
protected triples: BaseExecutionTriple[];
constructor(props: PropertyGetter, awsProps: PropertyGetter) {
super(props, awsProps);
this.triples = getExecutionTriplesForCurrentHost();
}
private async receiveMsg(url) {
try {
return await this.sqs.receiveMessage({
QueueUrl: url,
MaxNumberOfMessages: 1,
});
} catch (e) {
logger.error(`Error retreiving message from queue with URL: ${url}`);
throw e;
}
}
async pop(): Promise<RemoteExecutionMessage | undefined> {
const url = this.getSqsQueueUrl(this.triples[0]);
const queued_messages = await this.receiveMsg(url);
if (queued_messages.Messages && queued_messages.Messages.length === 1) {
const queued_message = queued_messages.Messages[0];
try {
if (queued_message.Body) {
const json = queued_message.Body;
return JSON.parse(json) as RemoteExecutionMessage;
} else {
return undefined;
}
} finally {
if (queued_message.ReceiptHandle) {
await this.sqs.deleteMessage({
QueueUrl: url,
ReceiptHandle: queued_message.ReceiptHandle,
});
}
}
}
return undefined;
}
}
async function sendResultViaWebsocket(compilationEnvironment, guid: string, result: BasicExecutionResult) {
try {
const sender = new EventsWsSender(compilationEnvironment.ceProps);
await sender.send(guid, result);
await sender.close();
} catch (error) {
logger.error(error);
}
}
async function doOneExecution(queue, compilationEnvironment) {
const msg = await queue.pop();
if (msg && msg.guid) {
try {
const executor = new LocalExecutionEnvironment(compilationEnvironment);
await executor.downloadExecutablePackage(msg.hash);
const result = await executor.execute(msg.params);
await sendResultViaWebsocket(compilationEnvironment, msg.guid, result);
} catch (e) {
// todo: e is undefined somehow?
logger.error(e);
await sendResultViaWebsocket(compilationEnvironment, msg.guid, {
code: -1,
stderr: [{text: 'Internal error when remotely executing'}],
stdout: [],
okToCache: false,
timedOut: false,
filenameTransform: f => f,
execTime: '0',
});
}
}
}
export function startExecutionWorkerThread(ceProps, awsProps, compilationEnvironment) {
const queue = new SqsWorkerMode(ceProps, awsProps);
// allow 2 executions at the same time
const doExecutionWork1 = async () => {
await doOneExecution(queue, compilationEnvironment);
setTimeout(doExecutionWork1, 100);
};
const doExecutionWork2 = async () => {
await doOneExecution(queue, compilationEnvironment);
setTimeout(doExecutionWork2, 100);
};
setTimeout(doExecutionWork1, 1500);
setTimeout(doExecutionWork2, 1530);
}

View File

@@ -22,7 +22,7 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
import {BypassCache, ExecutionParams} from '../../types/compilation/compilation.interfaces.js';
import {BypassCache, UnparsedExecutionParams} from '../../types/compilation/compilation.interfaces.js';
// IF YOU MODIFY ANYTHING HERE PLEASE UPDATE THE DOCUMENTATION!
@@ -40,7 +40,7 @@ export type CompileRequestQueryArgs = {
export type CompilationRequestArgs = {
userArguments: string;
compilerOptions: Record<string, any>;
executeParameters: ExecutionParams;
executeParameters: UnparsedExecutionParams;
filters: Record<string, boolean>;
tools: any;
libraries: any[];

View File

@@ -41,6 +41,7 @@ import {
BypassCache,
ExecutionParams,
FiledataPair,
UnparsedExecutionParams,
} from '../../types/compilation/compilation.interfaces.js';
import {CompilerOverrideOptions} from '../../types/compilation/compiler-overrides.interfaces.js';
import {CompilerInfo, PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
@@ -381,7 +382,7 @@ export class CompileHandler implements ICompileHandler {
filters: ParseFiltersAndOutputOptions,
bypassCache = BypassCache.None,
tools;
const execReqParams: ExecutionParams = {};
const execReqParams: UnparsedExecutionParams = {};
let libraries: any[] = [];
// IF YOU MODIFY ANYTHING HERE PLEASE UPDATE THE DOCUMENTATION!
if (req.is('json')) {

View File

@@ -38,6 +38,7 @@ export class HealthCheckHandler {
private readonly compilationQueue: CompilationQueue,
private readonly filePath: any,
private readonly compileHandler: ICompileHandler,
private readonly isExecutionWorker: boolean,
) {
this.handle = this._handle.bind(this);
}
@@ -55,7 +56,7 @@ export class HealthCheckHandler {
*/
await this.compilationQueue.enqueue(async () => {}, {highPriority: true});
if (!this.compileHandler.hasLanguages()) {
if (!this.isExecutionWorker && !this.compileHandler.hasLanguages()) {
logger.error(`*** HEALTH CHECK FAILURE: no languages/compilers detected`);
res.status(500).end();
return;

View File

@@ -151,6 +151,10 @@ export class InstructionSets {
target: [],
path: [],
},
x86: {
target: [],
path: [],
},
amd64: {
target: ['x86_64'],
path: ['/x86_64'],

View File

@@ -48,6 +48,8 @@ function debug(str: string) {
if (propDebug) logger.info(`prop: ${str}`);
}
export type PropFunc = (s: string, a?: any) => any;
export function get(base: string, property: string, defaultValue: any): PropertyValue;
export function get<T extends PropertyValue>(
base: string,
@@ -279,8 +281,8 @@ export function setDebug(debug: boolean) {
propDebug = debug;
}
export function fakeProps(fake: Record<string, PropertyValue>): PropertyGetter {
return (prop: string, def: any) => (fake[prop] === undefined ? def : fake[prop]);
export function fakeProps(fake: Record<string, PropertyValue>): PropFunc {
return (prop, def) => (fake[prop] === undefined ? def : fake[prop]);
}
export function getRawProperties() {

View File

@@ -42,7 +42,7 @@ export function getToolchainPathWithOptionsArr(compilerExe: string | null, optio
const gxxname = options.find(elem => elem.includes(icc_style_toolchain_flag));
if (gxxname) {
return path.resolve(path.dirname(gxxname.substring(11)), '..');
} else if (typeof compilerExe === 'string' && compilerExe.includes('/g++')) {
} else if (typeof compilerExe === 'string' && (compilerExe.includes('/g++') || compilerExe.endsWith('-g++'))) {
return path.resolve(path.dirname(compilerExe), '..');
} else {
return false;

718
package-lock.json generated
View File

@@ -12,6 +12,7 @@
"@aws-sdk/client-dynamodb": "^3.675.0",
"@aws-sdk/client-ec2": "^3.675.0",
"@aws-sdk/client-s3": "^3.675.0",
"@aws-sdk/client-sqs": "^3.614.0",
"@aws-sdk/client-ssm": "^3.675.0",
"@aws-sdk/credential-providers": "^3.675.0",
"@flatten-js/interval-tree": "^1.1.3",
@@ -75,6 +76,7 @@
"winston-loki": "^6.1.3",
"winston-papertrail": "^1.0.5",
"winston-transport": "^4.8.0",
"ws": "^8.18.0",
"yaml": "^2.6.0"
},
"devDependencies": {
@@ -576,6 +578,674 @@
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs": {
"version": "3.614.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sqs/-/client-sqs-3.614.0.tgz",
"integrity": "sha512-jCeHIlfwBSuoKN7Nf+DHYbH1eBuWALf+o9WaK8J+xhU0VE6G0DGdjHhjW1aTGTchBntARzqzMqwvY1e18Ac1zQ==",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
"@aws-sdk/client-sso-oidc": "3.614.0",
"@aws-sdk/client-sts": "3.614.0",
"@aws-sdk/core": "3.614.0",
"@aws-sdk/credential-provider-node": "3.614.0",
"@aws-sdk/middleware-host-header": "3.609.0",
"@aws-sdk/middleware-logger": "3.609.0",
"@aws-sdk/middleware-recursion-detection": "3.609.0",
"@aws-sdk/middleware-sdk-sqs": "3.614.0",
"@aws-sdk/middleware-user-agent": "3.614.0",
"@aws-sdk/region-config-resolver": "3.614.0",
"@aws-sdk/types": "3.609.0",
"@aws-sdk/util-endpoints": "3.614.0",
"@aws-sdk/util-user-agent-browser": "3.609.0",
"@aws-sdk/util-user-agent-node": "3.614.0",
"@smithy/config-resolver": "^3.0.5",
"@smithy/core": "^2.2.6",
"@smithy/fetch-http-handler": "^3.2.1",
"@smithy/hash-node": "^3.0.3",
"@smithy/invalid-dependency": "^3.0.3",
"@smithy/md5-js": "^3.0.3",
"@smithy/middleware-content-length": "^3.0.3",
"@smithy/middleware-endpoint": "^3.0.5",
"@smithy/middleware-retry": "^3.0.9",
"@smithy/middleware-serde": "^3.0.3",
"@smithy/middleware-stack": "^3.0.3",
"@smithy/node-config-provider": "^3.1.4",
"@smithy/node-http-handler": "^3.1.2",
"@smithy/protocol-http": "^4.0.3",
"@smithy/smithy-client": "^3.1.7",
"@smithy/types": "^3.3.0",
"@smithy/url-parser": "^3.0.3",
"@smithy/util-base64": "^3.0.0",
"@smithy/util-body-length-browser": "^3.0.0",
"@smithy/util-body-length-node": "^3.0.0",
"@smithy/util-defaults-mode-browser": "^3.0.9",
"@smithy/util-defaults-mode-node": "^3.0.9",
"@smithy/util-endpoints": "^2.0.5",
"@smithy/util-middleware": "^3.0.3",
"@smithy/util-retry": "^3.0.3",
"@smithy/util-utf8": "^3.0.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-crypto/sha256-browser": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz",
"integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==",
"dependencies": {
"@aws-crypto/sha256-js": "^5.2.0",
"@aws-crypto/supports-web-crypto": "^5.2.0",
"@aws-crypto/util": "^5.2.0",
"@aws-sdk/types": "^3.222.0",
"@aws-sdk/util-locate-window": "^3.0.0",
"@smithy/util-utf8": "^2.0.0",
"tslib": "^2.6.2"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz",
"integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==",
"dependencies": {
"@smithy/is-array-buffer": "^2.2.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz",
"integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==",
"dependencies": {
"@smithy/util-buffer-from": "^2.2.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-crypto/sha256-js": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz",
"integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==",
"dependencies": {
"@aws-crypto/util": "^5.2.0",
"@aws-sdk/types": "^3.222.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-crypto/supports-web-crypto": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz",
"integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==",
"dependencies": {
"tslib": "^2.6.2"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-crypto/util": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz",
"integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==",
"dependencies": {
"@aws-sdk/types": "^3.222.0",
"@smithy/util-utf8": "^2.0.0",
"tslib": "^2.6.2"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz",
"integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==",
"dependencies": {
"@smithy/is-array-buffer": "^2.2.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz",
"integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==",
"dependencies": {
"@smithy/util-buffer-from": "^2.2.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/client-sso": {
"version": "3.614.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.614.0.tgz",
"integrity": "sha512-p5pyYaxRzBttjBkqfc8i3K7DzBdTg3ECdVgBo6INIUxfvDy0J8QUE8vNtCgvFIkq+uPw/8M+Eo4zzln7anuO0Q==",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
"@aws-sdk/core": "3.614.0",
"@aws-sdk/middleware-host-header": "3.609.0",
"@aws-sdk/middleware-logger": "3.609.0",
"@aws-sdk/middleware-recursion-detection": "3.609.0",
"@aws-sdk/middleware-user-agent": "3.614.0",
"@aws-sdk/region-config-resolver": "3.614.0",
"@aws-sdk/types": "3.609.0",
"@aws-sdk/util-endpoints": "3.614.0",
"@aws-sdk/util-user-agent-browser": "3.609.0",
"@aws-sdk/util-user-agent-node": "3.614.0",
"@smithy/config-resolver": "^3.0.5",
"@smithy/core": "^2.2.6",
"@smithy/fetch-http-handler": "^3.2.1",
"@smithy/hash-node": "^3.0.3",
"@smithy/invalid-dependency": "^3.0.3",
"@smithy/middleware-content-length": "^3.0.3",
"@smithy/middleware-endpoint": "^3.0.5",
"@smithy/middleware-retry": "^3.0.9",
"@smithy/middleware-serde": "^3.0.3",
"@smithy/middleware-stack": "^3.0.3",
"@smithy/node-config-provider": "^3.1.4",
"@smithy/node-http-handler": "^3.1.2",
"@smithy/protocol-http": "^4.0.3",
"@smithy/smithy-client": "^3.1.7",
"@smithy/types": "^3.3.0",
"@smithy/url-parser": "^3.0.3",
"@smithy/util-base64": "^3.0.0",
"@smithy/util-body-length-browser": "^3.0.0",
"@smithy/util-body-length-node": "^3.0.0",
"@smithy/util-defaults-mode-browser": "^3.0.9",
"@smithy/util-defaults-mode-node": "^3.0.9",
"@smithy/util-endpoints": "^2.0.5",
"@smithy/util-middleware": "^3.0.3",
"@smithy/util-retry": "^3.0.3",
"@smithy/util-utf8": "^3.0.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/client-sso-oidc": {
"version": "3.614.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.614.0.tgz",
"integrity": "sha512-BI1NWcpppbHg/28zbUg54dZeckork8BItZIcjls12vxasy+p3iEzrJVG60jcbUTTsk3Qc1tyxNfrdcVqx0y7Ww==",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
"@aws-sdk/core": "3.614.0",
"@aws-sdk/credential-provider-node": "3.614.0",
"@aws-sdk/middleware-host-header": "3.609.0",
"@aws-sdk/middleware-logger": "3.609.0",
"@aws-sdk/middleware-recursion-detection": "3.609.0",
"@aws-sdk/middleware-user-agent": "3.614.0",
"@aws-sdk/region-config-resolver": "3.614.0",
"@aws-sdk/types": "3.609.0",
"@aws-sdk/util-endpoints": "3.614.0",
"@aws-sdk/util-user-agent-browser": "3.609.0",
"@aws-sdk/util-user-agent-node": "3.614.0",
"@smithy/config-resolver": "^3.0.5",
"@smithy/core": "^2.2.6",
"@smithy/fetch-http-handler": "^3.2.1",
"@smithy/hash-node": "^3.0.3",
"@smithy/invalid-dependency": "^3.0.3",
"@smithy/middleware-content-length": "^3.0.3",
"@smithy/middleware-endpoint": "^3.0.5",
"@smithy/middleware-retry": "^3.0.9",
"@smithy/middleware-serde": "^3.0.3",
"@smithy/middleware-stack": "^3.0.3",
"@smithy/node-config-provider": "^3.1.4",
"@smithy/node-http-handler": "^3.1.2",
"@smithy/protocol-http": "^4.0.3",
"@smithy/smithy-client": "^3.1.7",
"@smithy/types": "^3.3.0",
"@smithy/url-parser": "^3.0.3",
"@smithy/util-base64": "^3.0.0",
"@smithy/util-body-length-browser": "^3.0.0",
"@smithy/util-body-length-node": "^3.0.0",
"@smithy/util-defaults-mode-browser": "^3.0.9",
"@smithy/util-defaults-mode-node": "^3.0.9",
"@smithy/util-endpoints": "^2.0.5",
"@smithy/util-middleware": "^3.0.3",
"@smithy/util-retry": "^3.0.3",
"@smithy/util-utf8": "^3.0.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
},
"peerDependencies": {
"@aws-sdk/client-sts": "^3.614.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/client-sts": {
"version": "3.614.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.614.0.tgz",
"integrity": "sha512-i6QmaVA1KHHYNnI2VYQy/sc31rLm4+jSp8b/YbQpFnD0w3aXsrEEHHlxek45uSkHb4Nrj1omFBVy/xp1WVYx2Q==",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
"@aws-sdk/client-sso-oidc": "3.614.0",
"@aws-sdk/core": "3.614.0",
"@aws-sdk/credential-provider-node": "3.614.0",
"@aws-sdk/middleware-host-header": "3.609.0",
"@aws-sdk/middleware-logger": "3.609.0",
"@aws-sdk/middleware-recursion-detection": "3.609.0",
"@aws-sdk/middleware-user-agent": "3.614.0",
"@aws-sdk/region-config-resolver": "3.614.0",
"@aws-sdk/types": "3.609.0",
"@aws-sdk/util-endpoints": "3.614.0",
"@aws-sdk/util-user-agent-browser": "3.609.0",
"@aws-sdk/util-user-agent-node": "3.614.0",
"@smithy/config-resolver": "^3.0.5",
"@smithy/core": "^2.2.6",
"@smithy/fetch-http-handler": "^3.2.1",
"@smithy/hash-node": "^3.0.3",
"@smithy/invalid-dependency": "^3.0.3",
"@smithy/middleware-content-length": "^3.0.3",
"@smithy/middleware-endpoint": "^3.0.5",
"@smithy/middleware-retry": "^3.0.9",
"@smithy/middleware-serde": "^3.0.3",
"@smithy/middleware-stack": "^3.0.3",
"@smithy/node-config-provider": "^3.1.4",
"@smithy/node-http-handler": "^3.1.2",
"@smithy/protocol-http": "^4.0.3",
"@smithy/smithy-client": "^3.1.7",
"@smithy/types": "^3.3.0",
"@smithy/url-parser": "^3.0.3",
"@smithy/util-base64": "^3.0.0",
"@smithy/util-body-length-browser": "^3.0.0",
"@smithy/util-body-length-node": "^3.0.0",
"@smithy/util-defaults-mode-browser": "^3.0.9",
"@smithy/util-defaults-mode-node": "^3.0.9",
"@smithy/util-endpoints": "^2.0.5",
"@smithy/util-middleware": "^3.0.3",
"@smithy/util-retry": "^3.0.3",
"@smithy/util-utf8": "^3.0.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/core": {
"version": "3.614.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.614.0.tgz",
"integrity": "sha512-BUuS5/1YkgmKc4J0bg83XEtMyDHVyqG2QDzfmhYe8gbOIZabUl1FlrFVwhCAthtrrI6MPGTQcERB4BtJKUSplw==",
"dependencies": {
"@smithy/core": "^2.2.6",
"@smithy/protocol-http": "^4.0.3",
"@smithy/signature-v4": "^3.1.2",
"@smithy/smithy-client": "^3.1.7",
"@smithy/types": "^3.3.0",
"fast-xml-parser": "4.2.5",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/credential-provider-env": {
"version": "3.609.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.609.0.tgz",
"integrity": "sha512-v69ZCWcec2iuV9vLVJMa6fAb5xwkzN4jYIT8yjo2c4Ia/j976Q+TPf35Pnz5My48Xr94EFcaBazrWedF+kwfuQ==",
"dependencies": {
"@aws-sdk/types": "3.609.0",
"@smithy/property-provider": "^3.1.3",
"@smithy/types": "^3.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/credential-provider-http": {
"version": "3.614.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.614.0.tgz",
"integrity": "sha512-YIEjlNUKb3Vo/iTnGAPdsiDC3FUUnNoex2OwU8LmR7AkYZiWdB8nx99DfgkkY+OFMUpw7nKD2PCOtuFONelfGA==",
"dependencies": {
"@aws-sdk/types": "3.609.0",
"@smithy/fetch-http-handler": "^3.2.1",
"@smithy/node-http-handler": "^3.1.2",
"@smithy/property-provider": "^3.1.3",
"@smithy/protocol-http": "^4.0.3",
"@smithy/smithy-client": "^3.1.7",
"@smithy/types": "^3.3.0",
"@smithy/util-stream": "^3.0.6",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/credential-provider-ini": {
"version": "3.614.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.614.0.tgz",
"integrity": "sha512-KfLuLFGwlvFSZ2MuzYwWGPb1y5TeiwX5okIDe0aQ1h10oD3924FXbN+mabOnUHQ8EFcGAtCaWbrC86mI7ktC6A==",
"dependencies": {
"@aws-sdk/credential-provider-env": "3.609.0",
"@aws-sdk/credential-provider-http": "3.614.0",
"@aws-sdk/credential-provider-process": "3.614.0",
"@aws-sdk/credential-provider-sso": "3.614.0",
"@aws-sdk/credential-provider-web-identity": "3.609.0",
"@aws-sdk/types": "3.609.0",
"@smithy/credential-provider-imds": "^3.1.4",
"@smithy/property-provider": "^3.1.3",
"@smithy/shared-ini-file-loader": "^3.1.4",
"@smithy/types": "^3.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
},
"peerDependencies": {
"@aws-sdk/client-sts": "^3.614.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/credential-provider-node": {
"version": "3.614.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.614.0.tgz",
"integrity": "sha512-4J6gPEuFZP0mkWq5E//oMS1vrmMM88iNNcv7TEljYnsc6JTAlKejCyFwx6CN+nkIhmIZsl06SXIhBemzBdBPfg==",
"dependencies": {
"@aws-sdk/credential-provider-env": "3.609.0",
"@aws-sdk/credential-provider-http": "3.614.0",
"@aws-sdk/credential-provider-ini": "3.614.0",
"@aws-sdk/credential-provider-process": "3.614.0",
"@aws-sdk/credential-provider-sso": "3.614.0",
"@aws-sdk/credential-provider-web-identity": "3.609.0",
"@aws-sdk/types": "3.609.0",
"@smithy/credential-provider-imds": "^3.1.4",
"@smithy/property-provider": "^3.1.3",
"@smithy/shared-ini-file-loader": "^3.1.4",
"@smithy/types": "^3.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/credential-provider-process": {
"version": "3.614.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.614.0.tgz",
"integrity": "sha512-Q0SI0sTRwi8iNODLs5+bbv8vgz8Qy2QdxbCHnPk/6Cx6LMf7i3dqmWquFbspqFRd8QiqxStrblwxrUYZi09tkA==",
"dependencies": {
"@aws-sdk/types": "3.609.0",
"@smithy/property-provider": "^3.1.3",
"@smithy/shared-ini-file-loader": "^3.1.4",
"@smithy/types": "^3.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/credential-provider-sso": {
"version": "3.614.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.614.0.tgz",
"integrity": "sha512-55+gp0JY4451cWI1qXmVMFM0GQaBKiQpXv2P0xmd9P3qLDyeFUSEW8XPh0d2lb1ICr6x4s47ynXVdGCIv2mXMg==",
"dependencies": {
"@aws-sdk/client-sso": "3.614.0",
"@aws-sdk/token-providers": "3.614.0",
"@aws-sdk/types": "3.609.0",
"@smithy/property-provider": "^3.1.3",
"@smithy/shared-ini-file-loader": "^3.1.4",
"@smithy/types": "^3.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/credential-provider-web-identity": {
"version": "3.609.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.609.0.tgz",
"integrity": "sha512-U+PG8NhlYYF45zbr1km3ROtBMYqyyj/oK8NRp++UHHeuavgrP+4wJ4wQnlEaKvJBjevfo3+dlIBcaeQ7NYejWg==",
"dependencies": {
"@aws-sdk/types": "3.609.0",
"@smithy/property-provider": "^3.1.3",
"@smithy/types": "^3.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
},
"peerDependencies": {
"@aws-sdk/client-sts": "^3.609.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/middleware-host-header": {
"version": "3.609.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.609.0.tgz",
"integrity": "sha512-iTKfo158lc4jLDfYeZmYMIBHsn8m6zX+XB6birCSNZ/rrlzAkPbGE43CNdKfvjyWdqgLMRXF+B+OcZRvqhMXPQ==",
"dependencies": {
"@aws-sdk/types": "3.609.0",
"@smithy/protocol-http": "^4.0.3",
"@smithy/types": "^3.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/middleware-logger": {
"version": "3.609.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz",
"integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==",
"dependencies": {
"@aws-sdk/types": "3.609.0",
"@smithy/types": "^3.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/middleware-recursion-detection": {
"version": "3.609.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.609.0.tgz",
"integrity": "sha512-6sewsYB7/o/nbUfA99Aa/LokM+a/u4Wpm/X2o0RxOsDtSB795ObebLJe2BxY5UssbGaWkn7LswyfvrdZNXNj1w==",
"dependencies": {
"@aws-sdk/types": "3.609.0",
"@smithy/protocol-http": "^4.0.3",
"@smithy/types": "^3.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/middleware-user-agent": {
"version": "3.614.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.614.0.tgz",
"integrity": "sha512-xUxh0UPQiMTG6E31Yvu6zVYlikrIcFDKljM11CaatInzvZubGTGiX0DjpqRlfGzUNsuPc/zNrKwRP2+wypgqIw==",
"dependencies": {
"@aws-sdk/types": "3.609.0",
"@aws-sdk/util-endpoints": "3.614.0",
"@smithy/protocol-http": "^4.0.3",
"@smithy/types": "^3.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/region-config-resolver": {
"version": "3.614.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz",
"integrity": "sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==",
"dependencies": {
"@aws-sdk/types": "3.609.0",
"@smithy/node-config-provider": "^3.1.4",
"@smithy/types": "^3.3.0",
"@smithy/util-config-provider": "^3.0.0",
"@smithy/util-middleware": "^3.0.3",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/token-providers": {
"version": "3.614.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz",
"integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==",
"dependencies": {
"@aws-sdk/types": "3.609.0",
"@smithy/property-provider": "^3.1.3",
"@smithy/shared-ini-file-loader": "^3.1.4",
"@smithy/types": "^3.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
},
"peerDependencies": {
"@aws-sdk/client-sso-oidc": "^3.614.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/types": {
"version": "3.609.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz",
"integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==",
"dependencies": {
"@smithy/types": "^3.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/util-endpoints": {
"version": "3.614.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz",
"integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==",
"dependencies": {
"@aws-sdk/types": "3.609.0",
"@smithy/types": "^3.3.0",
"@smithy/util-endpoints": "^2.0.5",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/util-user-agent-browser": {
"version": "3.609.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz",
"integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==",
"dependencies": {
"@aws-sdk/types": "3.609.0",
"@smithy/types": "^3.3.0",
"bowser": "^2.11.0",
"tslib": "^2.6.2"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@aws-sdk/util-user-agent-node": {
"version": "3.614.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.614.0.tgz",
"integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==",
"dependencies": {
"@aws-sdk/types": "3.609.0",
"@smithy/node-config-provider": "^3.1.4",
"@smithy/types": "^3.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
},
"peerDependencies": {
"aws-crt": ">=1.0.0"
},
"peerDependenciesMeta": {
"aws-crt": {
"optional": true
}
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@smithy/is-array-buffer": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz",
"integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@smithy/signature-v4": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-3.1.2.tgz",
"integrity": "sha512-3BcPylEsYtD0esM4Hoyml/+s7WP2LFhcM3J2AGdcL2vx9O60TtfpDOL72gjb4lU8NeRPeKAwR77YNyyGvMbuEA==",
"dependencies": {
"@smithy/is-array-buffer": "^3.0.0",
"@smithy/types": "^3.3.0",
"@smithy/util-hex-encoding": "^3.0.0",
"@smithy/util-middleware": "^3.0.3",
"@smithy/util-uri-escape": "^3.0.0",
"@smithy/util-utf8": "^3.0.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@smithy/signature-v4/node_modules/@smithy/is-array-buffer": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz",
"integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/@smithy/util-stream": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.0.6.tgz",
"integrity": "sha512-w9i//7egejAIvplX821rPWWgaiY1dxsQUw0hXX7qwa/uZ9U3zplqTQ871jWadkcVB9gFDhkPWYVZf4yfFbZ0xA==",
"dependencies": {
"@smithy/fetch-http-handler": "^3.2.1",
"@smithy/node-http-handler": "^3.1.2",
"@smithy/types": "^3.3.0",
"@smithy/util-base64": "^3.0.0",
"@smithy/util-buffer-from": "^3.0.0",
"@smithy/util-hex-encoding": "^3.0.0",
"@smithy/util-utf8": "^3.0.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/client-sqs/node_modules/fast-xml-parser": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz",
"integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==",
"funding": [
{
"type": "paypal",
"url": "https://paypal.me/naturalintelligence"
},
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"dependencies": {
"strnum": "^1.0.5"
},
"bin": {
"fxparser": "src/cli/cli.js"
}
},
"node_modules/@aws-sdk/client-ssm": {
"version": "3.675.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.675.0.tgz",
@@ -1153,6 +1823,34 @@
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/middleware-sdk-sqs": {
"version": "3.614.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sqs/-/middleware-sdk-sqs-3.614.0.tgz",
"integrity": "sha512-TFBbXEMnzBqGVPatL5Pg8a3kPOUrhSWxXXWZjr6S4D5ffCJnCNSzfi09SUoehe6uYmTQlS7AAqugTIFdRnA/ww==",
"dependencies": {
"@aws-sdk/types": "3.609.0",
"@smithy/smithy-client": "^3.1.7",
"@smithy/types": "^3.3.0",
"@smithy/util-hex-encoding": "^3.0.0",
"@smithy/util-utf8": "^3.0.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/middleware-sdk-sqs/node_modules/@aws-sdk/types": {
"version": "3.609.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz",
"integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==",
"dependencies": {
"@smithy/types": "^3.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@aws-sdk/middleware-ssec": {
"version": "3.667.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.667.0.tgz",
@@ -15973,6 +16671,26 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"node_modules/ws": {
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",

View File

@@ -21,6 +21,7 @@
"@aws-sdk/client-dynamodb": "^3.675.0",
"@aws-sdk/client-ec2": "^3.675.0",
"@aws-sdk/client-s3": "^3.675.0",
"@aws-sdk/client-sqs": "^3.614.0",
"@aws-sdk/client-ssm": "^3.675.0",
"@aws-sdk/credential-providers": "^3.675.0",
"@flatten-js/interval-tree": "^1.1.3",
@@ -84,6 +85,7 @@
"winston-loki": "^6.1.3",
"winston-papertrail": "^1.0.5",
"winston-transport": "^4.8.0",
"ws": "^8.18.0",
"yaml": "^2.6.0"
},
"devDependencies": {

View File

@@ -1181,7 +1181,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
if (filters.binary && !this.compiler.supportsBinary) {
delete filters.binary;
}
if (filters.execute && !this.compiler.supportsExecute) {
if (filters.execute && !this.compiler.supportsExecute && !this.compiler.supportsBinary) {
delete filters.execute;
}
if (filters.libraryCode && !this.compiler.supportsLibraryCodeFilter) {
@@ -2772,7 +2772,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
this.filterBinaryButton.prop('disabled', !this.compiler.supportsBinary || filters.binaryObject);
formatFilterTitle(this.filterBinaryButton, this.filterBinaryTitle);
this.filterExecuteButton.prop('disabled', !this.compiler.supportsExecute);
this.filterExecuteButton.prop('disabled', !this.compiler.supportsBinary && !this.compiler.supportsExecute);
formatFilterTitle(this.filterExecuteButton, this.filterExecuteTitle);
// Disable demangle for compilers where we can't access it
this.filterDemangleButton.prop('disabled', !this.compiler.supportsDemangle);
@@ -2846,7 +2846,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
this.gccDumpButton.toggle(!!this.compiler.supportsGccDump);
this.gnatDebugTreeButton.toggle(!!this.compiler.supportsGnatDebugViews);
this.gnatDebugButton.toggle(!!this.compiler.supportsGnatDebugViews);
this.executorButton.toggle(!!this.compiler.supportsExecute);
this.executorButton.toggle(this.compiler.supportsBinary || this.compiler.supportsExecute);
this.filterBinaryButton.toggle(!!this.compiler.supportsBinary);
this.filterBinaryObjectButton.toggle(!!this.compiler.supportsBinaryObject);
this.filterVerboseDemanglingButton.toggle(!!this.compiler.supportsVerboseDemangling);

View File

@@ -214,7 +214,7 @@ export class Executor extends Pane<ExecutorState> {
}
compilerIsVisible(compiler: CompilerInfo): boolean {
return !!compiler.supportsExecute;
return !!(compiler.supportsExecute || compiler.supportsBinary);
}
getEditorIdByFilename(filename: string): number | null {
@@ -315,7 +315,7 @@ export class Executor extends Pane<ExecutorState> {
}
compileFromEditorSource(options: CompilationRequestOptions, bypassCache?: BypassCache): void {
if (!this.compiler?.supportsExecute) {
if (!this.compiler || !this.compilerIsVisible(this.compiler)) {
this.alertSystem.notify('This compiler (' + this.compiler?.name + ') does not support execution', {
group: 'execution',
});
@@ -629,6 +629,9 @@ export class Executor extends Pane<ExecutorState> {
if (!result.didExecute) {
this.executionStatusSection.append($('<div/>').text('Could not execute the program'));
if (execStderr.length > 0) {
this.handleOutput(execStderr, this.executionStatusSection, this.normalAnsiToHtml, false);
}
this.executionStatusSection.append($('<div/>').text('Compiler returned: ' + buildResultCode));
}
// reset stream styles
@@ -1281,9 +1284,9 @@ export class Executor extends Pane<ExecutorState> {
);
if (!allCompilers) return [];
const hasAtLeastOneExecuteSupported = Object.values(allCompilers).some(compiler => {
return compiler.supportsExecute !== false;
});
const hasAtLeastOneExecuteSupported = Object.values(allCompilers).some(compiler =>
this.compilerIsVisible(compiler),
);
if (!hasAtLeastOneExecuteSupported) {
this.compiler = null;
@@ -1292,7 +1295,7 @@ export class Executor extends Pane<ExecutorState> {
return Object.values(allCompilers).filter(compiler => {
return (
(compiler.hidden !== true && compiler.supportsExecute !== false) ||
(compiler.hidden !== true && this.compilerIsVisible(compiler)) ||
(this.compiler && compiler.id === this.compiler.id)
);
});

View File

@@ -22,13 +22,15 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
import {beforeAll, describe, expect, it} from 'vitest';
import {afterAll, beforeAll, describe, expect, it} from 'vitest';
import {BaseCompiler} from '../lib/base-compiler.js';
import {BuildEnvSetupBase} from '../lib/buildenvsetup/index.js';
import {CompilationEnvironment} from '../lib/compilation-env.js';
import {ClangCompiler} from '../lib/compilers/clang.js';
import {RustCompiler} from '../lib/compilers/rust.js';
import {Win32Compiler} from '../lib/compilers/win32.js';
import * as props from '../lib/properties.js';
import {splitArguments} from '../lib/utils.js';
import {CompilerOverrideType, ConfiguredOverrides} from '../types/compilation/compiler-overrides.interfaces.js';
import {CompilerInfo} from '../types/compiler.interfaces.js';
@@ -44,6 +46,7 @@ import {
const languages = {
'c++': {id: 'c++'},
rust: {id: 'rust'},
} as const;
describe('Basic compiler invariants', () => {
@@ -752,3 +755,66 @@ describe('Target hints', () => {
expect(iset).toBe('riscv64');
});
});
describe('Rust overrides', () => {
let ce: CompilationEnvironment;
const executingCompilerInfo = makeFakeCompilerInfo({
remote: {
target: '',
path: '',
cmakePath: '',
},
semver: 'nightly',
lang: 'rust',
ldPath: [],
libPath: [],
supportsExecute: true,
supportsBinary: true,
options: '',
});
beforeAll(() => {
ce = makeCompilationEnvironment({
languages,
});
props.initialize(path.resolve('./test/test-properties/rust'), ['local']);
});
afterAll(() => {
props.reset();
});
it('Empty options check', () => {
const compiler = new RustCompiler(executingCompilerInfo, ce);
expect(compiler.changeOptionsBasedOnOverrides([], [])).toEqual([]);
});
it('Should change linker if target is aarch64', () => {
const compiler = new RustCompiler(executingCompilerInfo, ce);
const originalOptions = compiler.optionsForFilter(
{
binary: true,
execute: true,
},
'output.txt',
[],
);
expect(originalOptions).toEqual([
'-C',
'debuginfo=1',
'-o',
'output.txt',
'--crate-type',
'bin',
'-Clinker=/usr/amd64/bin/gcc',
]);
expect(
compiler.changeOptionsBasedOnOverrides(originalOptions, [
{
name: CompilerOverrideType.arch,
value: 'aarch64-linux-something',
},
]),
).toEqual(['-C', 'debuginfo=1', '-o', 'output.txt', '--crate-type', 'bin', '-Clinker=/usr/aarch64/bin/gcc']);
});
});

View File

@@ -43,28 +43,28 @@ describe('Compilation environment', () => {
it('Should cache by default', async () => {
// TODO: Work will need to be done here when CompilationEnvironment's constructor is typed better
const ce = new CompilationEnvironment(compilerProps, undefined, undefined);
const ce = new CompilationEnvironment(compilerProps, fakeProps({}), undefined, undefined);
await expect(ce.cacheGet('foo')).resolves.toBeNull();
await ce.cachePut('foo', {res: 'bar'}, undefined);
await expect(ce.cacheGet('foo')).resolves.toEqual({res: 'bar'});
await expect(ce.cacheGet('baz')).resolves.toBeNull();
});
it('Should cache when asked', async () => {
const ce = new CompilationEnvironment(compilerProps, undefined, true);
const ce = new CompilationEnvironment(compilerProps, fakeProps({}), undefined, true);
await expect(ce.cacheGet('foo')).resolves.toBeNull();
await ce.cachePut('foo', {res: 'bar'}, undefined);
await expect(ce.cacheGet('foo')).resolves.toEqual({res: 'bar'});
});
it("Shouldn't cache when asked", async () => {
// TODO: Work will need to be done here when CompilationEnvironment's constructor is typed better
const ce = new CompilationEnvironment(compilerProps, undefined, false);
const ce = new CompilationEnvironment(compilerProps, fakeProps({}), undefined, false);
await expect(ce.cacheGet('foo')).resolves.toBeNull();
await ce.cachePut('foo', {res: 'bar'}, undefined);
await expect(ce.cacheGet('foo')).resolves.toBeNull();
});
it('Should filter bad options', () => {
// TODO: Work will need to be done here when CompilationEnvironment's constructor is typed better
const ce = new CompilationEnvironment(compilerProps, undefined, undefined);
const ce = new CompilationEnvironment(compilerProps, fakeProps({}), undefined, undefined);
expect(ce.findBadOptions(['-O3', '-flto'])).toEqual([]);
expect(ce.findBadOptions(['-O3', '-plugin'])).toEqual(['-plugin']);
});

View File

@@ -0,0 +1,78 @@
import {describe, expect, it} from 'vitest';
import {BinaryInfoLinux} from '../lib/binaries/binary-utils.js';
import {BaseExecutionTriple, ExecutionSpecialty} from '../lib/execution/base-execution-triple.js';
import {getExecutionTriplesForCurrentHost, matchesCurrentHost} from '../lib/execution/execution-triple.js';
describe('Execution triple utils', () => {
it('default always matches', () => {
const triples: BaseExecutionTriple[] = getExecutionTriplesForCurrentHost();
expect(matchesCurrentHost(triples[0])).toEqual(true);
});
it('can parse a thing', () => {
const triple = new BaseExecutionTriple();
triple.parse('aarch64-linux-cpu');
expect(triple.instructionSet).toEqual('aarch64');
expect(triple.os).toEqual('linux');
expect(triple.specialty).toEqual(ExecutionSpecialty.cpu);
});
it('would parse nvgpu', () => {
const triple = new BaseExecutionTriple();
triple.parse('amd64-linux-nvgpu');
expect(triple.instructionSet).toEqual('amd64');
expect(triple.os).toEqual('linux');
expect(triple.specialty).toEqual(ExecutionSpecialty.nvgpu);
});
it('recognizes aarch64', () => {
const info = BinaryInfoLinux.parseFileInfo(
'ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 5.17.0, with debug_info, not stripped',
);
expect(info?.instructionSet).toEqual('aarch64');
expect(info?.os).toEqual('linux');
});
it('recognizes arm32', () => {
const info = BinaryInfoLinux.parseFileInfo(
'ELF 32-bit LSB executable, ARM, EABI5 version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 4.4.255, with debug_info, not stripped',
);
expect(info?.instructionSet).toEqual('arm32');
expect(info?.os).toEqual('linux');
});
it('recognizes lin64', () => {
const info = BinaryInfoLinux.parseFileInfo(
'ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=9def7a0f68cf33177d0d8566b152af24d9ec1ac4, for GNU/Linux 3.2.0, stripped',
);
expect(info?.instructionSet).toEqual('amd64');
expect(info?.os).toEqual('linux');
});
it('recognizes win64', () => {
const info = BinaryInfoLinux.parseFileInfo(
'PE32+ executable (DLL) (console) x86-64 (stripped to external PDB), for MS Windows, 12 sections',
);
expect(info?.instructionSet).toEqual('amd64');
expect(info?.os).toEqual('win32');
});
it('recognizes win alternatives', () => {
const filteredLine = BinaryInfoLinux.removeComments(
'PE32+ executable (DLL) (console) Aarch64 (stripped to external PDB)',
);
expect(filteredLine).toEqual('PE32+ executable Aarch64');
const info = BinaryInfoLinux.parseFileInfo(
'PE32+ executable (DLL) (console) Aarch64 (stripped to external PDB), for MS Windows, 12 sections',
);
expect(info?.instructionSet).toEqual('aarch64');
expect(info?.os).toEqual('win32');
});
it('recognizes win32', () => {
const info = BinaryInfoLinux.parseFileInfo('PE32 executable (GUI) Intel 80386, for MS Windows, 4 sections');
expect(info?.instructionSet).toEqual('x86');
expect(info?.os).toEqual('win32');
});
it('recognizes avr', () => {
const info = BinaryInfoLinux.parseFileInfo(
'ELF 32-bit LSB executable, Atmel AVR 8-bit, version 1 (SYSV), statically linked, with debug_info, not stripped',
);
expect(info?.instructionSet).toEqual('avr');
expect(info?.os).toEqual('linux');
});
});

View File

@@ -40,7 +40,7 @@ describe('Health checks', () => {
};
compilationQueue = new CompilationQueue(1, 0, 0);
app = express();
app.use('/hc', new HealthCheckHandler(compilationQueue, '', compileHandlerMock).handle);
app.use('/hc', new HealthCheckHandler(compilationQueue, '', compileHandlerMock, false).handle);
});
it('should respond with OK', async () => {
@@ -67,7 +67,7 @@ describe('Health checks without lang/comp', () => {
};
compilationQueue = new CompilationQueue(1, 0, 0);
app = express();
app.use('/hc', new HealthCheckHandler(compilationQueue, '', compileHandlerMock).handle);
app.use('/hc', new HealthCheckHandler(compilationQueue, '', compileHandlerMock, false).handle);
});
it('should respond with error', async () => {
@@ -75,6 +75,24 @@ describe('Health checks without lang/comp', () => {
});
});
describe('Health checks without lang/comp but in execution worker mode', () => {
let app;
let compilationQueue;
beforeEach(() => {
const compileHandlerMock = {
hasLanguages: () => false,
};
compilationQueue = new CompilationQueue(1, 0, 0);
app = express();
app.use('/hc', new HealthCheckHandler(compilationQueue, '', compileHandlerMock, true).handle);
});
it('should respond with ok', async () => {
await request(app).get('/hc').expect(200);
});
});
describe('Health checks on disk', () => {
let app;
@@ -85,8 +103,8 @@ describe('Health checks on disk', () => {
const compilationQueue = new CompilationQueue(1, 0, 0);
app = express();
app.use('/hc', new HealthCheckHandler(compilationQueue, '/fake/.nonexist', compileHandlerMock).handle);
app.use('/hc2', new HealthCheckHandler(compilationQueue, '/fake/.health', compileHandlerMock).handle);
app.use('/hc', new HealthCheckHandler(compilationQueue, '/fake/.nonexist', compileHandlerMock, false).handle);
app.use('/hc2', new HealthCheckHandler(compilationQueue, '/fake/.health', compileHandlerMock, false).handle);
mockfs({
'/fake': {

View File

@@ -164,7 +164,7 @@ describe('Library directories (c++)', () => {
expect(fmtpaths).not.toContain('-I/tmp/compiler-explorer-compiler-123/fmt/include');
expect(fmtpaths).toContain('-I/opt/compiler-explorer/libs/fmt/1.0/include');
const qtpaths = (compiler as any).getIncludeArguments(
const qtpaths = (compiler as BaseCompiler).getIncludeArguments(
[{id: 'qt', version: '660'}],
'/tmp/compiler-explorer-compiler-123',
);
@@ -177,8 +177,16 @@ describe('Library directories (c++)', () => {
it('should set LD_LIBRARY_PATH when executing', () => {
(compiler as any).sandboxType = 'nsjail';
const qtpaths = (compiler as any).getSharedLibraryPathsAsLdLibraryPathsForExecution(
[{id: 'qt', version: '660'}],
const qtpaths = (compiler as BaseCompiler).getSharedLibraryPathsAsLdLibraryPathsForExecution(
{
libraries: [{id: 'qt', version: '660'}],
compiler: undefined,
source: '',
options: [],
backendOptions: undefined,
tools: [],
files: [],
},
'/tmp/compiler-explorer-compiler-123',
);

View File

@@ -0,0 +1,2 @@
linker=/usr/amd64/bin/gcc
aarch64linker=/usr/aarch64/bin/gcc

View File

@@ -80,7 +80,7 @@ describe('CompilerDropInTool', () => {
]);
});
it('Should not support riscv gcc compilers', () => {
it('Should maybe support riscv gcc compilers', () => {
const tool = new CompilerDropinTool({} as ToolInfo, {} as ToolEnv);
const compilationInfo = {
@@ -95,7 +95,11 @@ describe('CompilerDropInTool', () => {
const sourcefile = 'example.cpp';
const orderedArgs = tool.getOrderedArguments(compilationInfo, includeflags, [], args, sourcefile);
expect(orderedArgs).toEqual(false);
// note: toolchain twice because reasons, see CompilerDropinTool getOrderedArguments()
expect(orderedArgs).toEqual([
'--gcc-toolchain=' + path.resolve('/opt/compiler-explorer/riscv64/gcc-8.2.0/riscv64-unknown-linux-gnu'),
'--gcc-toolchain=' + path.resolve('/opt/compiler-explorer/riscv64/gcc-8.2.0/riscv64-unknown-linux-gnu'),
]);
});
it('Should support ICC compilers', () => {

View File

@@ -41,7 +41,7 @@ import {Language} from '../types/languages.interfaces.js';
export function makeCompilationEnvironment(options: Record<string, any>): CompilationEnvironment {
const compilerProps = new CompilerProps(options.languages, fakeProps(options.props || {}));
const compilationQueue = options.queue || new CompilationQueue(options.concurrency || 1, options.timeout, 100_000);
return new CompilationEnvironment(compilerProps, compilationQueue, options.doCache);
return new CompilationEnvironment(compilerProps, fakeProps({}), compilationQueue, options.doCache);
}
export function makeFakeCompilerInfo(props: Partial<CompilerInfo>): CompilerInfo {

View File

@@ -48,6 +48,12 @@ export type ActiveTool = {
stdin: string;
};
export type UnparsedExecutionParams = {
args?: string | string[];
stdin?: string;
runtimeTools?: ConfiguredRuntimeTools;
};
export type ExecutionParams = {
args?: string[];
stdin?: string;
@@ -109,7 +115,7 @@ export type CompilationRequestOptions = {
customOutputFilename?: string;
overrides?: ConfiguredOverrides;
};
executeParameters: ExecutionParams;
executeParameters: UnparsedExecutionParams;
filters: ParseFiltersAndOutputOptions;
tools: ActiveTool[];
libraries: SelectedLibraryVersion[];

View File

@@ -26,6 +26,7 @@ export const InstructionSetsList = [
'6502',
'aarch64',
'amd64',
'x86',
'arm32',
'avr',
'beam',