Add more typings (#6082)

This commit is contained in:
Matt Godbolt
2024-02-04 13:33:19 -06:00
committed by GitHub
parent 31dd08be80
commit c26a2924fc
4 changed files with 52 additions and 38 deletions

View File

@@ -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,
};

View File

@@ -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"

View File

@@ -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
View File

@@ -0,0 +1,6 @@
{
"extends": "./tsconfig.backend.json",
"files": [],
"include": ["test/**/*.js", "test/**/*.ts"],
"exclude": []
}