judge: pass envirent vars to checker

This commit is contained in:
undefined committed 2022-02-08 19:10:18 +08:00
1 parent 9158550139
commit abec5fd3ec
11 files changed
+54 -47

No files matched your search

+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@hydrooj/hydrojudge",
"bin": "bin/hydrojudge.js",
"version": "2.12.17",
"version": "2.13.0",
"main": "package.json",
"author": "undefined <i@undefined.moe>",
"repository": "https://github.com/hydro-dev/Hydro.git",
+2 -22
View File
@@ -3,36 +3,16 @@ import { findFileSync } from '@hydrooj/utils/lib/utils';
import checkers from './checkers';
import compile from './compile';
import { SystemError } from './error';
import { Execute } from './interface';
import { CopyInFile } from './sandbox/interface';
import { CheckConfig, Execute } from './interface';
import { parseFilename } from './utils';
const testlibSrc = findFileSync('@hydrooj/hydrojudge/vendor/testlib/testlib.h');
interface CheckConfig {
checker_type: string;
stdin: CopyInFile,
stdout: CopyInFile,
user_stdout: CopyInFile,
user_stderr: CopyInFile,
copyIn?: Record<string, CopyInFile>,
score: number,
detail: boolean,
}
export async function check(config: CheckConfig): Promise<[number, number, string]> {
if (!checkers[config.checker_type]) throw new SystemError('Unknown checker type {0}', [config.checker_type]);
const {
code, status, score, message,
} = await checkers[config.checker_type]({
input: config.stdin,
output: config.stdout,
user_stdout: config.user_stdout,
user_stderr: config.user_stderr,
score: config.score,
copyIn: config.copyIn || {},
detail: config.detail,
});
} = await checkers[config.checker_type](config);
if (code) throw new SystemError('Checker returned {0}.', [code]);
return [status, score, message];
}
+3 -18
View File
@@ -1,27 +1,10 @@
/* eslint-disable no-template-curly-in-string */
import { STATUS } from '@hydrooj/utils/lib/status';
import { SystemError } from './error';
import { CheckConfig, CheckResult } from './interface';
import { run } from './sandbox';
import { CopyInFile } from './sandbox/interface';
import { parse } from './testlib';
interface CheckConfig {
input: CopyInFile,
output: CopyInFile,
user_stdout: CopyInFile,
user_stderr: CopyInFile,
copyIn: Record<string, CopyInFile>,
score: number,
detail: boolean,
}
interface CheckResult {
status: number,
score: number,
message: string,
code?: number,
}
type Checker = (config: CheckConfig) => Promise<CheckResult>;
const checkers: Record<string, Checker> = {
@@ -129,6 +112,7 @@ const checkers: Record<string, Checker> = {
...config.copyIn,
},
copyOut: ['score', 'message'],
env: config.env,
});
const { message } = files;
const score = parseInt(files.score, 10);
@@ -196,6 +180,7 @@ const checkers: Record<string, Checker> = {
answer: config.output,
...config.copyIn,
},
env: config.env,
});
if (status === STATUS.STATUS_SYSTEM_ERROR) {
return {
+8
View File
@@ -38,6 +38,7 @@ class JudgeTask {
data: any[];
folder: string;
config: any;
env: Record<string, string>;
getLang: (name: string) => LangConfig;
constructor(session: Hydro, request, ws: WebSocket) {
@@ -63,6 +64,13 @@ class JudgeTask {
this.source = this.request.source;
this.tmpdir = path.resolve(getConfig('tmp_dir'), this.host, this.rid);
this.clean = [];
this.env = {
HYDRO_DOMAIN: this.request.domainId.toString(),
HYDRO_RECORD: this.rid,
HYDRO_LANG: this.lang,
HYDRO_USER: this.request.uid.toString(),
HYDRO_CONTEST: this.request.tid?.toString() || '',
};
await Lock.acquire(`${this.host}/${this.source}/${this.rid}`);
fs.ensureDirSync(this.tmpdir);
tmpfs.mount(this.tmpdir, getConfig('tmpfs_size'));
+21
View File
@@ -1,12 +1,33 @@
import { CopyInFile } from './sandbox/interface';
export interface Execute {
execute: string,
clean: Function,
copyIn: Record<string, CopyInFile>,
time?: number,
}
export interface CompileErrorInfo {
stdout?: string,
stderr?: string,
status?: number
}
export interface CheckConfig {
checker_type: string;
input: CopyInFile;
output: CopyInFile;
user_stdout: CopyInFile;
user_stderr: CopyInFile;
copyIn: Record<string, CopyInFile>;
score: number;
detail: boolean;
env?: Record<string, string>;
}
export interface CheckResult {
status: number,
score: number,
message: string,
code?: number,
}
+4 -3
View File
@@ -67,14 +67,15 @@ function judgeCase(c: Case, sid: string) {
status = STATUS.STATUS_MEMORY_LIMIT_EXCEEDED;
} else {
[status, score, message] = await check({
copyIn: ctx.checker.copyIn,
stdin: { src: c.input },
stdout: { src: c.output },
copyIn: ctx.checker.copyIn || {},
input: { src: c.input },
output: { src: c.output },
user_stdout: stdout,
user_stderr: stderr,
checker_type: ctx.config.checker_type,
score: ctxSubtask.subtask.score,
detail: ctx.config.detail ?? true,
env: ctx.env,
});
}
} else if (status === STATUS.STATUS_RUNTIME_ERROR && code) {
+2 -2
View File
@@ -97,8 +97,8 @@ export const judge = async (ctx: Context) => {
} else {
[status, , message] = await check({
copyIn: copyInDir(path.resolve(ctx.tmpdir, 'checker')),
stdin: { src: input },
stdout: { src: stdout },
input: { src: input },
output: { src: stdout },
user_stdout: { src: stdout },
user_stderr: { src: stderr },
checker_type: ctx.config.checker_type,
@@ -35,6 +35,7 @@ function judgeCase(c: Case) {
time: ctxSubtask.subtask.time * 2 * ctx.executeInteractor.time,
memory: ctxSubtask.subtask.memory * 2,
copyOut: ['/w/tout?'],
env: ctx.env,
},
);
// TODO handle tout (maybe pass to checker?)
@@ -32,6 +32,7 @@ export interface JudgeTaskInterface {
input?: string;
clean: Function[];
config: Config;
env?: Record<string, string>;
}
export interface RuntimeContext {
+3 -1
View File
@@ -39,6 +39,7 @@ interface Parameter {
copyOut?: string[];
copyOutCached?: string[];
cacheStdoutAndStderr?: boolean;
env?: Record<string, string>;
}
interface SandboxAdaptedResult {
@@ -72,6 +73,7 @@ function proc({
processLimit = getConfig('processLimit'),
stdin = '', copyIn = {}, copyOut = [], copyOutCached = [],
cacheStdoutAndStderr = false,
env = {},
}: Parameter = {}): Cmd {
if (!supportOptional) {
copyOut = (copyOut as string[]).map((i) => (i.endsWith('?') ? i.substr(0, i.length - 1) : i));
@@ -84,7 +86,7 @@ function proc({
}
return {
args: parseArgs(execute),
env: getConfig('env').split('\n'),
env: [...getConfig('env').split('\n'), ...Object.keys(env).map((i) => `${i}=${env[i].replace(/=/g, '\\=')}`)],
files: [
stdin ? { src: stdin } : { content: '' },
{ name: 'stdout', max: Math.floor(1024 * 1024 * size) },
+8
View File
@@ -150,6 +150,7 @@ async function postInit() {
code: string;
data: any[];
config: any;
env: any;
input?: string;
next: (data: any, id?: number) => void;
end: (data: any) => void;
@@ -176,6 +177,13 @@ async function postInit() {
this.source = this.request.source;
this.config = this.request.config;
this.input = this.request.input;
this.env = {
HYDRO_DOMAIN: this.request.domainId.toString(),
HYDRO_RECORD: this.rid,
HYDRO_LANG: this.lang,
HYDRO_USER: this.request.uid.toString(),
HYDRO_CONTEST: this.request.tid?.toString() || '',
};
this.next = getNext(this);
this.end = getEnd(this.rid);
this.tmpdir = path.resolve(getConfig('tmp_dir'), this.rid);