mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2025-12-27 07:04:04 -05:00
Add more typings (#6082)
This commit is contained in:
80
lib/exec.ts
80
lib/exec.ts
@@ -36,18 +36,19 @@ import type {FilenameTransformFunc, UnprocessedExecResult} from '../types/execut
|
||||
import {logger} from './logger.js';
|
||||
import {propsFor} from './properties.js';
|
||||
import {Graceful} from './node-graceful.js';
|
||||
import {unwrapString} from './assert.js';
|
||||
import {unwrapString, unwrap, assert} from './assert.js';
|
||||
import os from 'os';
|
||||
import {Stream} from 'stream';
|
||||
|
||||
type NsJailOptions = {
|
||||
args: string[];
|
||||
options: ExecutionOptions;
|
||||
filenameTransform: FilenameTransformFunc;
|
||||
filenameTransform: FilenameTransformFunc | undefined;
|
||||
};
|
||||
|
||||
const execProps = propsFor('execution');
|
||||
|
||||
function setupOnError(stream, name) {
|
||||
function setupOnError(stream: Stream, name: string) {
|
||||
if (stream === undefined) return;
|
||||
stream.on('error', err => {
|
||||
logger.error(`Error with ${name} stream:`, err);
|
||||
@@ -116,7 +117,7 @@ export function executeDirect(
|
||||
streams.stderr += '\nKilled - processing time exceeded\n';
|
||||
}, timeoutMs);
|
||||
|
||||
function setupStream(stream, name) {
|
||||
function setupStream(stream: Stream, name: string) {
|
||||
if (stream === undefined) return;
|
||||
stream.on('data', data => {
|
||||
if (streams.truncated) return;
|
||||
@@ -222,7 +223,7 @@ export function getNsJailOptions(
|
||||
}
|
||||
|
||||
const homeDir = '/app';
|
||||
let filenameTransform;
|
||||
let filenameTransform: FilenameTransformFunc | undefined;
|
||||
if (options.customCwd) {
|
||||
let replacement = options.customCwd;
|
||||
if (options.appHome) {
|
||||
@@ -314,28 +315,28 @@ export function getExecuteCEWrapperOptions(command: string, args: string[], opti
|
||||
return getCeWrapperOptions('execute', command, args, options);
|
||||
}
|
||||
|
||||
function sandboxNsjail(command, args, options) {
|
||||
function sandboxNsjail(command: string, args: string[], options: ExecutionOptions) {
|
||||
logger.info('Sandbox execution via nsjail', {command, args});
|
||||
const nsOpts = getSandboxNsjailOptions(command, args, options);
|
||||
return executeDirect(execProps<string>('nsjail'), nsOpts.args, nsOpts.options, nsOpts.filenameTransform);
|
||||
}
|
||||
|
||||
function executeNsjail(command, args, options) {
|
||||
function executeNsjail(command: string, args: string[], options: ExecutionOptions) {
|
||||
const nsOpts = getNsJailOptions('execute', command, args, options);
|
||||
return executeDirect(execProps<string>('nsjail'), nsOpts.args, nsOpts.options, nsOpts.filenameTransform);
|
||||
}
|
||||
|
||||
function sandboxCEWrapper(command, args, options) {
|
||||
function sandboxCEWrapper(command: string, args: string[], options: ExecutionOptions) {
|
||||
const nsOpts = getSandboxCEWrapperOptions(command, args, options);
|
||||
return executeDirect(execProps<string>('cewrapper'), nsOpts.args, nsOpts.options, nsOpts.filenameTransform);
|
||||
}
|
||||
|
||||
function executeCEWrapper(command, args, options) {
|
||||
function executeCEWrapper(command: string, args: string[], options: ExecutionOptions) {
|
||||
const nsOpts = getExecuteCEWrapperOptions(command, args, options);
|
||||
return executeDirect(execProps<string>('cewrapper'), nsOpts.args, nsOpts.options, nsOpts.filenameTransform);
|
||||
}
|
||||
|
||||
function withFirejailTimeout(args: string[], options?) {
|
||||
function withFirejailTimeout(args: string[], options?: ExecutionOptions) {
|
||||
if (options && options.timeoutMs) {
|
||||
// const ExtraWallClockLeewayMs = 1000;
|
||||
const ExtraCpuLeewayMs = 1500;
|
||||
@@ -344,7 +345,7 @@ function withFirejailTimeout(args: string[], options?) {
|
||||
return args;
|
||||
}
|
||||
|
||||
function sandboxFirejail(command: string, args: string[], options) {
|
||||
function sandboxFirejail(command: string, args: string[], options: ExecutionOptions) {
|
||||
logger.info('Sandbox execution via firejail', {command, args});
|
||||
const execPath = path.dirname(command);
|
||||
const execName = path.basename(command);
|
||||
@@ -362,8 +363,9 @@ function sandboxFirejail(command: string, args: string[], options) {
|
||||
delete options.ldPath;
|
||||
}
|
||||
|
||||
for (const key of Object.keys(options.env || {})) {
|
||||
jailingOptions.push(`--env=${key}=${options.env[key]}`);
|
||||
const env = options.env || {};
|
||||
for (const key of Object.keys(env)) {
|
||||
jailingOptions.push(`--env=${key}=${env[key]}`);
|
||||
}
|
||||
delete options.env;
|
||||
|
||||
@@ -371,7 +373,7 @@ function sandboxFirejail(command: string, args: string[], options) {
|
||||
}
|
||||
|
||||
const sandboxDispatchTable = {
|
||||
none: (command, args, options) => {
|
||||
none: (command: string, args: string[], options: ExecutionOptions) => {
|
||||
logger.info('Sandbox execution (sandbox disabled)', {command, args});
|
||||
if (needsWine(command)) {
|
||||
return executeWineDirect(command, args, options);
|
||||
@@ -412,7 +414,7 @@ export function startWineInit() {
|
||||
const executionType = execProps('executionType', 'none');
|
||||
// We need to fire up a firejail wine server even in nsjail world (for now).
|
||||
const firejail = executionType === 'firejail' || executionType === 'nsjail' ? execProps<string>('firejail') : null;
|
||||
const env = applyWineEnv({PATH: process.env.PATH});
|
||||
const env = applyWineEnv({PATH: unwrapString(process.env.PATH)});
|
||||
const prefix = env.WINEPREFIX;
|
||||
|
||||
logger.info(`Initialising WINE in ${prefix}`);
|
||||
@@ -433,7 +435,7 @@ export function startWineInit() {
|
||||
// We wait until the process has printed out some known good text, but don't wait
|
||||
// for it to exit (it won't, on purpose).
|
||||
|
||||
let wineServer;
|
||||
let wineServer: child_process.ChildProcess | undefined;
|
||||
if (firejail) {
|
||||
logger.info(`Starting a new, firejailed, long-lived wineserver complex`);
|
||||
wineServer = child_process.spawn(
|
||||
@@ -462,7 +464,7 @@ export function startWineInit() {
|
||||
Graceful.on('exit', () => {
|
||||
const waitingPromises: Promise<void>[] = [];
|
||||
|
||||
function waitForExit(process, name): Promise<void> {
|
||||
function waitForExit(process: child_process.ChildProcess, name: string): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
process.on('close', () => {
|
||||
logger.info(`Process '${name}' closed`);
|
||||
@@ -477,29 +479,33 @@ export function startWineInit() {
|
||||
if (wineServer.killed) {
|
||||
waitingPromises.push(waitForExit(wineServer, 'WINE server'));
|
||||
}
|
||||
wineServer = null;
|
||||
wineServer = undefined;
|
||||
}
|
||||
return Promise.all(waitingPromises);
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
setupOnError(wineServer.stdin, 'stdin');
|
||||
setupOnError(wineServer.stdout, 'stdout');
|
||||
setupOnError(wineServer.stderr, 'stderr');
|
||||
assert(wineServer);
|
||||
const [stdin, stdout, stderr] = [
|
||||
unwrap(wineServer.stdin),
|
||||
unwrap(wineServer.stdout),
|
||||
unwrap(wineServer.stderr),
|
||||
];
|
||||
setupOnError(stdin, 'stdin');
|
||||
setupOnError(stdout, 'stdout');
|
||||
setupOnError(stderr, 'stderr');
|
||||
const magicString = '!!EVERYTHING IS WORKING!!';
|
||||
wineServer.stdin.write(`echo ${magicString}`);
|
||||
stdin.write(`echo ${magicString}`);
|
||||
|
||||
let output = '';
|
||||
wineServer.stdout.on('data', data => {
|
||||
stdout.on('data', data => {
|
||||
logger.info(`Output from wine server complex: ${data.toString().trim()}`);
|
||||
output += data;
|
||||
if (output.includes(magicString)) {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
wineServer.stderr.on('data', data =>
|
||||
logger.info(`stderr output from wine server complex: ${data.toString().trim()}`),
|
||||
);
|
||||
stderr.on('data', data => logger.info(`stderr output from wine server complex: ${data.toString().trim()}`));
|
||||
wineServer.on('error', e => {
|
||||
logger.error(`WINE server complex exited with error ${e}`);
|
||||
reject(e);
|
||||
@@ -513,29 +519,29 @@ export function startWineInit() {
|
||||
wineInitPromise = asyncSetup();
|
||||
}
|
||||
|
||||
function applyWineEnv(env) {
|
||||
function applyWineEnv(env: Record<string, string>): Record<string, string> {
|
||||
return {
|
||||
...env,
|
||||
// Force use of wine vcruntime (See change 45106c382)
|
||||
WINEDLLOVERRIDES: 'vcruntime140=b',
|
||||
WINEDEBUG: '-all',
|
||||
WINEPREFIX: execProps('winePrefix'),
|
||||
WINEPREFIX: execProps<string>('winePrefix'),
|
||||
};
|
||||
}
|
||||
|
||||
function needsWine(command) {
|
||||
function needsWine(command: string) {
|
||||
return command.match(/\.exe$/i) && process.platform === 'linux' && !process.env.wsl;
|
||||
}
|
||||
|
||||
async function executeWineDirect(command, args, options) {
|
||||
async function executeWineDirect(command: string, args: string[], options: ExecutionOptions) {
|
||||
options = _.clone(options) || {};
|
||||
options.env = applyWineEnv(options.env);
|
||||
options.env = applyWineEnv(options.env || {});
|
||||
args = [command, ...args];
|
||||
await wineInitPromise;
|
||||
return await executeDirect(unwrapString(execProps<string>('wine')), args, options);
|
||||
}
|
||||
|
||||
async function executeFirejail(command, args, options) {
|
||||
async function executeFirejail(command: string, args: string[], options: ExecutionOptions) {
|
||||
options = _.clone(options) || {};
|
||||
const firejail = execProps<string>('firejail');
|
||||
const baseOptions = withFirejailTimeout(
|
||||
@@ -544,9 +550,9 @@ async function executeFirejail(command, args, options) {
|
||||
);
|
||||
if (needsWine(command)) {
|
||||
logger.debug('WINE execution via firejail', {command, args});
|
||||
options.env = applyWineEnv(options.env);
|
||||
options.env = applyWineEnv(options.env || {});
|
||||
args = [command, ...args];
|
||||
command = execProps('wine');
|
||||
command = execProps<string>('wine');
|
||||
baseOptions.push('--profile=' + getFirejailProfileFilePath('wine'), `--join=${wineSandboxName}`);
|
||||
delete options.customCwd;
|
||||
baseOptions.push(command);
|
||||
@@ -562,7 +568,7 @@ async function executeFirejail(command, args, options) {
|
||||
delete options.ldPath;
|
||||
}
|
||||
|
||||
let filenameTransform;
|
||||
let filenameTransform: FilenameTransformFunc | undefined;
|
||||
if (options.customCwd) {
|
||||
baseOptions.push(`--private=${options.customCwd}`);
|
||||
const replacement = options.customCwd;
|
||||
@@ -579,7 +585,7 @@ async function executeFirejail(command, args, options) {
|
||||
return await executeDirect(firejail, baseOptions.concat(args), options, filenameTransform);
|
||||
}
|
||||
|
||||
async function executeNone(command, args, options) {
|
||||
async function executeNone(command: string, args: string[], options: ExecutionOptions) {
|
||||
if (needsWine(command)) {
|
||||
return await executeWineDirect(command, args, options);
|
||||
}
|
||||
@@ -589,7 +595,7 @@ async function executeNone(command, args, options) {
|
||||
const executeDispatchTable = {
|
||||
none: executeNone,
|
||||
firejail: executeFirejail,
|
||||
nsjail: (command, args, options) =>
|
||||
nsjail: (command: string, args: string[], options: ExecutionOptions) =>
|
||||
needsWine(command) ? executeFirejail(command, args, options) : executeNsjail(command, args, options),
|
||||
cewrapper: executeCEWrapper,
|
||||
};
|
||||
|
||||
@@ -183,7 +183,7 @@
|
||||
"format": "prettier --write .",
|
||||
"format-files": "prettier --write --ignore-unknown",
|
||||
"ts-compile": "tsc",
|
||||
"ts-check": "tsc -p ./tsconfig.backend.json --noEmit && tsc -p ./tsconfig.frontend.json --noEmit",
|
||||
"ts-check": "tsc -p ./tsconfig.backend.json --noEmit && tsc -p ./tsconfig.frontend.json --noEmit && tsc -p ./tsconfig.tests.json --noEmit",
|
||||
"webpack": "node --no-warnings=ExperimentalWarning --loader ts-node/esm ./node_modules/webpack-cli/bin/cli.js --node-env=production --config webpack.config.esm.ts"
|
||||
},
|
||||
"license": "BSD-2-Clause"
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
import path from 'path';
|
||||
|
||||
import {assert} from '../lib/assert.js';
|
||||
import * as exec from '../lib/exec.js';
|
||||
import * as props from '../lib/properties.js';
|
||||
import {UnprocessedExecResult} from '../types/execution/execution.interfaces.js';
|
||||
@@ -230,6 +231,7 @@ describe('Execution tests', () => {
|
||||
]);
|
||||
options.should.deep.equals({});
|
||||
expect(filenameTransform).to.not.be.undefined;
|
||||
assert(filenameTransform);
|
||||
filenameTransform('moo').should.equal('moo');
|
||||
filenameTransform('/some/custom/cwd/file').should.equal('/app/file');
|
||||
});
|
||||
|
||||
6
tsconfig.tests.json
Normal file
6
tsconfig.tests.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "./tsconfig.backend.json",
|
||||
"files": [],
|
||||
"include": ["test/**/*.js", "test/**/*.ts"],
|
||||
"exclude": []
|
||||
}
|
||||
Reference in New Issue
Block a user