mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-19 17:38:19 +08:00
core: update judge config
This commit is contained in:
1 parent
d13876a5bc
commit
a2004056ac
22 files changed
+100
-245
No files matched your search
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@hydrooj/hydrojudge",
|
||||
"bin": "bin/hydrojudge.js",
|
||||
"version": "2.13.8",
|
||||
"version": "2.14.0",
|
||||
"main": "package.json",
|
||||
"author": "undefined <i@undefined.moe>",
|
||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||
|
||||
@@ -155,7 +155,7 @@ async function read1(folder: string, files: string[], checkFile, cfg, rst) {
|
||||
return config;
|
||||
}
|
||||
|
||||
async function readAutoCases(folder, { next }, cfg, rst) {
|
||||
async function readAutoCases(folder: string, { next }, cfg, rst) {
|
||||
const config = {
|
||||
checker_type: 'default',
|
||||
count: 0,
|
||||
@@ -177,7 +177,7 @@ async function readAutoCases(folder, { next }, cfg, rst) {
|
||||
let result = await read0(folder, files, checkFile, cfg);
|
||||
if (!result.count) result = await read1(folder, files, checkFile, cfg, rst);
|
||||
Object.assign(config, result);
|
||||
next({ message: { message: 'Found {0} testcases.', params: [config.count] } });
|
||||
if (cfg.isSelfSubmission) next({ message: { message: 'Found {0} testcases.', params: [config.count] } });
|
||||
} catch (e) {
|
||||
throw new SystemError('Cannot parse testdata.', [e.message, ...e.params]);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import checkers from './checkers';
|
||||
import compile from './compile';
|
||||
import { SystemError } from './error';
|
||||
import { CheckConfig, Execute } from './interface';
|
||||
import { parseFilename } from './utils';
|
||||
|
||||
const testlibSrc = findFileSync('@hydrooj/hydrojudge/vendor/testlib/testlib.h');
|
||||
|
||||
@@ -21,6 +20,15 @@ export async function compileChecker(getLang: Function, checkerType: string, che
|
||||
if (!checkers[checkerType]) throw new SystemError('Unknown checker type {0}.', [checkerType]);
|
||||
if (checkerType === 'testlib') copyIn['testlib.h'] = { src: testlibSrc };
|
||||
const file = await fs.readFile(checker);
|
||||
const s = checker.replace('@', '.').split('.');
|
||||
let lang;
|
||||
let langId = s.pop();
|
||||
while (s.length) {
|
||||
lang = getLang(langId, false);
|
||||
if (lang) break;
|
||||
langId = `${s.pop()}.${langId}`;
|
||||
}
|
||||
if (!lang) throw new SystemError('Unknown checker language.');
|
||||
// TODO cache compiled checker
|
||||
return await compile(getLang(parseFilename(checker).split('.')[1].replace('@', '.')), file.toString(), 'checker', copyIn);
|
||||
return await compile(lang, file.toString(), copyIn);
|
||||
}
|
||||
@@ -79,7 +79,7 @@ const checkers: Record<string, Checker> = {
|
||||
* exit code:返回判断结果
|
||||
*/
|
||||
async hustoj(config) {
|
||||
const { code, stdout } = await run('${dir}/checker input answer usrout', {
|
||||
const { code, stdout } = await run(`${config.execute} input answer usrout`, {
|
||||
copyIn: {
|
||||
usrout: config.user_stdout,
|
||||
answer: config.output,
|
||||
@@ -104,7 +104,7 @@ const checkers: Record<string, Checker> = {
|
||||
* argv[6]:输出错误报告的文件
|
||||
*/
|
||||
async lemon(config) {
|
||||
const { files } = await run(`\${dir}/checker input usrout answer ${config.score} score message`, {
|
||||
const { files } = await run(`${config.execute} input usrout answer ${config.score} score message`, {
|
||||
copyIn: {
|
||||
usrout: config.user_stdout,
|
||||
answer: config.output,
|
||||
@@ -131,7 +131,7 @@ const checkers: Record<string, Checker> = {
|
||||
* exit code:返回判断结果
|
||||
*/
|
||||
async qduoj(config) {
|
||||
const { status, stdout } = await run('${dir}/checker input usrout', {
|
||||
const { status, stdout } = await run(`${config.execute} input usrout`, {
|
||||
copyIn: {
|
||||
usrout: config.user_stdout,
|
||||
input: config.input,
|
||||
@@ -157,7 +157,7 @@ const checkers: Record<string, Checker> = {
|
||||
*/
|
||||
async syzoj(config) {
|
||||
// eslint-disable-next-line prefer-const
|
||||
let { status, stdout, stderr } = await run('${dir}/checker', {
|
||||
let { status, stdout, stderr } = await run(config.execute, {
|
||||
copyIn: {
|
||||
input: config.input,
|
||||
user_out: config.user_stdout,
|
||||
@@ -173,7 +173,7 @@ const checkers: Record<string, Checker> = {
|
||||
},
|
||||
|
||||
async testlib(config) {
|
||||
const { stderr, status } = await run('${dir}/checker ${dir}/in ${dir}/user_out ${dir}/answer', {
|
||||
const { stderr, status } = await run(`${config.execute} /w/in /w/user_out /w/answer`, {
|
||||
copyIn: {
|
||||
in: config.input,
|
||||
user_out: config.user_stdout,
|
||||
|
||||
@@ -7,15 +7,15 @@ import { CopyInFile } from './sandbox/interface';
|
||||
import { compilerText } from './utils';
|
||||
|
||||
export = async function compile(
|
||||
lang: LangConfig, code: string, target: string, copyIn: Record<string, CopyInFile> = {}, next?: Function,
|
||||
lang: LangConfig, code: string, copyIn: Record<string, CopyInFile> = {}, next?: Function,
|
||||
): Promise<Execute> {
|
||||
target = lang.target || target;
|
||||
const target = lang.target || 'foo';
|
||||
copyIn[lang.code_file] = { content: code };
|
||||
if (lang.compile) {
|
||||
const {
|
||||
status, stdout, stderr, fileIds,
|
||||
} = await run(
|
||||
lang.compile.replace(/\$\{name\}/g, target),
|
||||
lang.compile,
|
||||
{ copyIn, copyOutCached: [target] },
|
||||
);
|
||||
if (status !== STATUS.STATUS_ACCEPTED) throw new CompileError({ status, stdout, stderr });
|
||||
|
||||
@@ -112,7 +112,11 @@ class JudgeTask {
|
||||
this.stat.read_cases = new Date();
|
||||
this.config = await readCases(
|
||||
this.folder,
|
||||
{ detail: this.session.config.detail, ...this.config },
|
||||
{
|
||||
detail: this.session.config.detail,
|
||||
isSelfSubmission: this.config.problemOwner === this.request.uid,
|
||||
...this.config,
|
||||
},
|
||||
{ next: this.next, key: md5(`${this.source}/${getConfig('secret')}`) },
|
||||
);
|
||||
this.stat.judge = new Date();
|
||||
@@ -243,10 +247,11 @@ export default class Hydro {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
getLang(name: string) {
|
||||
getLang(name: string, doThrow = true) {
|
||||
if (this.language[name]) return this.language[name];
|
||||
if (name === 'cpp' && this.language.cc) return this.language.cc;
|
||||
throw new SystemError('Unsupported language {0}', [name]);
|
||||
if (doThrow) throw new SystemError('Unsupported language {0}', [name]);
|
||||
return null;
|
||||
}
|
||||
|
||||
async consume(queue: Queue<any>) {
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as vj4, default } from './vj4';
|
||||
export { default as hydro } from './hydro';
|
||||
export { default as vj4 } from './vj4';
|
||||
export { default as hydro, default } from './hydro';
|
||||
@@ -1,6 +1,8 @@
|
||||
export default class VJ4 {
|
||||
constructor() {
|
||||
console.log('新版本不再支持 VJ4。请降级至 hydrojudge@2.5.21 或迁移到 Hydro。');
|
||||
console.log('This version of HydroJudge nolonger supports VJ4. Please downgrade to');
|
||||
console.log('hydrojudge@2.5.21 or migrate to Hydro.');
|
||||
console.log('详细文档: https://hydro.js.org/ ');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ export interface CompileErrorInfo {
|
||||
}
|
||||
|
||||
export interface CheckConfig {
|
||||
execute: string;
|
||||
checker_type: string;
|
||||
input: CopyInFile;
|
||||
output: CopyInFile;
|
||||
|
||||
@@ -41,7 +41,7 @@ function judgeCase(c: Case, sid: string) {
|
||||
const copyOutCached = filename ? [`${filename}.out?`] : [];
|
||||
const stdin = filename ? null : c.input;
|
||||
const res = await run(
|
||||
ctx.execute.execute.replace(/\$\{name\}/g, 'code'),
|
||||
ctx.execute.execute,
|
||||
{
|
||||
stdin,
|
||||
copyIn,
|
||||
@@ -67,6 +67,7 @@ function judgeCase(c: Case, sid: string) {
|
||||
status = STATUS.STATUS_MEMORY_LIMIT_EXCEEDED;
|
||||
} else {
|
||||
[status, score, message] = await check({
|
||||
execute: ctx.checker.execute,
|
||||
copyIn: ctx.checker.copyIn || {},
|
||||
input: { src: c.input },
|
||||
output: { src: c.output },
|
||||
@@ -142,15 +143,15 @@ export const judge = async (ctx: Context) => {
|
||||
} else throw new CompileError('Language not supported by provided templates');
|
||||
}
|
||||
[ctx.execute, ctx.checker] = await Promise.all([
|
||||
compile(
|
||||
ctx.getLang(ctx.lang), ctx.code,
|
||||
Object.fromEntries(
|
||||
(ctx.config.user_extra_files || []).map((i) => [i.split('/').pop(), { src: i }]),
|
||||
),
|
||||
ctx.next,
|
||||
),
|
||||
(() => {
|
||||
const copyIn = {};
|
||||
for (const file of ctx.config.user_extra_files) {
|
||||
copyIn[parseFilename(file)] = { src: file };
|
||||
}
|
||||
return compile(ctx.getLang(ctx.lang), ctx.code, 'code', copyIn, ctx.next);
|
||||
})(),
|
||||
(() => {
|
||||
if (!ctx.config.checker_type || ['default', 'strict'].includes(ctx.config.checker_type)) {
|
||||
if (['default', 'strict'].includes(ctx.config.checker_type || 'default')) {
|
||||
return { execute: '', copyIn: {}, clean: () => Promise.resolve(null) };
|
||||
}
|
||||
const copyIn = {};
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
// Not implemented
|
||||
import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import { STATUS } from '@hydrooj/utils/lib/status';
|
||||
import { check, compileChecker } from '../check';
|
||||
import compile from '../compile';
|
||||
import { CompileError } from '../error';
|
||||
import { run } from '../sandbox';
|
||||
import signals from '../signals';
|
||||
import { copyInDir, parseFilename } from '../utils';
|
||||
import { Context } from './interface';
|
||||
|
||||
export const judge = async (ctx: Context) => {
|
||||
if (ctx.config.template) {
|
||||
if (ctx.config.template[ctx.lang]) {
|
||||
const tpl = ctx.config.template[ctx.lang];
|
||||
ctx.code = tpl[0] + ctx.code + tpl[1];
|
||||
} else throw new CompileError('Language not supported by provided templates');
|
||||
}
|
||||
ctx.next({ status: STATUS.STATUS_COMPILING });
|
||||
if (!ctx.config.validator || !ctx.config.std) throw new CompileError('config.validator or config.std is missing.');
|
||||
const [execute, executeValidator, executeStd, executeChecker] = await Promise.all([
|
||||
// UserProgram
|
||||
(() => {
|
||||
const copyIn = {};
|
||||
for (const file of ctx.config.user_extra_files) {
|
||||
copyIn[parseFilename(file)] = { src: file };
|
||||
}
|
||||
return compile(ctx.getLang(ctx.lang), ctx.code, 'code', copyIn, ctx.next);
|
||||
})(),
|
||||
// Validator
|
||||
(async () => {
|
||||
const copyIn = {};
|
||||
for (const file of ctx.config.judge_extra_files) {
|
||||
copyIn[parseFilename(file)] = { src: file };
|
||||
}
|
||||
const file = await fs.readFile(ctx.config.validator);
|
||||
return await compile(ctx.getLang(parseFilename(ctx.config.validator).split('.')[1]), file.toString(), 'validator', copyIn);
|
||||
})(),
|
||||
// Std
|
||||
(async () => {
|
||||
const copyIn = {};
|
||||
for (const file of ctx.config.user_extra_files) {
|
||||
copyIn[parseFilename(file)] = { src: file };
|
||||
}
|
||||
const file = await fs.readFile(ctx.config.std);
|
||||
return await compile(ctx.getLang(parseFilename(ctx.config.std).split('.')[1]), file.toString(), 'std', copyIn);
|
||||
})(),
|
||||
// Checker
|
||||
(() => {
|
||||
if (!ctx.config.checker_type || ctx.config.checker_type === 'default') return null;
|
||||
const copyIn = {};
|
||||
for (const file of ctx.config.judge_extra_files) {
|
||||
copyIn[parseFilename(file)] = { src: file };
|
||||
}
|
||||
return compileChecker(
|
||||
ctx.getLang,
|
||||
ctx.config.checker_type,
|
||||
ctx.config.checker,
|
||||
copyIn,
|
||||
);
|
||||
})(),
|
||||
]);
|
||||
ctx.clean.push(execute.clean, executeValidator.clean, executeStd.clean, executeChecker.clean);
|
||||
ctx.next({ status: STATUS.STATUS_JUDGING, progress: 0 });
|
||||
const { filename } = ctx.config;
|
||||
const input = path.resolve(ctx.tmpdir, 'input');
|
||||
await fs.writeFile(input, ctx.config.hack);
|
||||
if (filename) execute.copyIn[`${filename}.in`] = { src: input };
|
||||
const copyOut = filename ? [`${filename}.out`] : [];
|
||||
const stdin = filename ? null : input;
|
||||
const stdout = path.resolve(ctx.tmpdir, 'user.out');
|
||||
const stderr = path.resolve(ctx.tmpdir, 'user.err');
|
||||
const res = await run(
|
||||
ctx.execute.execute.replace(/\$\{name\}/g, 'code'),
|
||||
{
|
||||
stdin,
|
||||
stdout: filename ? null : stdout,
|
||||
stderr,
|
||||
copyIn: execute.copyIn,
|
||||
copyOut,
|
||||
time: 1000,
|
||||
memory: 512,
|
||||
},
|
||||
);
|
||||
const { code, time_usage_ms, memory_usage_kb } = res;
|
||||
let { status } = res;
|
||||
if (res.files[`${filename}.out`] || !fs.existsSync(stdout)) {
|
||||
fs.writeFileSync(stdout, res.files[`${filename}.out`] || '');
|
||||
}
|
||||
let message = '';
|
||||
if (status === STATUS.STATUS_ACCEPTED) {
|
||||
if (time_usage_ms > 1000) {
|
||||
status = STATUS.STATUS_TIME_LIMIT_EXCEEDED;
|
||||
} else if (memory_usage_kb > 512 * 1024) {
|
||||
status = STATUS.STATUS_MEMORY_LIMIT_EXCEEDED;
|
||||
} else {
|
||||
[status, , message] = await check({
|
||||
copyIn: copyInDir(path.resolve(ctx.tmpdir, 'checker')),
|
||||
input: { src: input },
|
||||
output: { src: stdout },
|
||||
user_stdout: { src: stdout },
|
||||
user_stderr: { src: stderr },
|
||||
checker_type: ctx.config.checker_type,
|
||||
score: 100,
|
||||
detail: ctx.config.detail,
|
||||
});
|
||||
}
|
||||
} else if (status === STATUS.STATUS_RUNTIME_ERROR && code) {
|
||||
if (code < 32) message = signals[code];
|
||||
else message = `您的程序返回了 ${code}.`;
|
||||
}
|
||||
ctx.next({
|
||||
status: STATUS.STATUS_JUDGING,
|
||||
case: {
|
||||
status,
|
||||
score: 0,
|
||||
time_ms: time_usage_ms,
|
||||
memory_kb: memory_usage_kb,
|
||||
message,
|
||||
},
|
||||
});
|
||||
|
||||
ctx.stat.done = new Date();
|
||||
ctx.next({ message: JSON.stringify(ctx.stat) });
|
||||
ctx.end({
|
||||
status,
|
||||
score: ctx.total_score,
|
||||
time_ms: Math.floor(ctx.total_time_usage_ms * 1000000) / 1000000,
|
||||
memory_kb: ctx.total_memory_usage_kb,
|
||||
});
|
||||
};
|
||||
@@ -1,10 +1,9 @@
|
||||
import * as def from './default';
|
||||
import * as hack from './hack';
|
||||
import * as interactive from './interactive';
|
||||
import { Context } from './interface';
|
||||
import * as run from './run';
|
||||
import * as submit_answer from './submit_answer';
|
||||
|
||||
export = {
|
||||
default: def, interactive, run, submit_answer, hack, objective: submit_answer,
|
||||
default: def, interactive, run, submit_answer, objective: submit_answer,
|
||||
} as Record<string, { judge(ctx: Context): Promise<void> }>;
|
||||
@@ -24,13 +24,13 @@ function judgeCase(c: Case) {
|
||||
ctx.executeInteractor.copyIn.out = c.output ? { src: c.output } : { content: '' };
|
||||
const [{ code, time_usage_ms, memory_usage_kb }, resInteractor] = await runPiped(
|
||||
{
|
||||
execute: ctx.executeUser.execute.replace(/\$\{name\}/g, 'code'),
|
||||
execute: ctx.executeUser.execute,
|
||||
copyIn: ctx.executeUser.copyIn,
|
||||
time: ctxSubtask.subtask.time * ctx.executeUser.time,
|
||||
memory: ctxSubtask.subtask.memory,
|
||||
},
|
||||
{
|
||||
execute: `${ctx.executeInteractor.execute.replace(/\$\{name\}/g, 'interactor')} /w/in /w/tout /w/out`,
|
||||
execute: `${ctx.executeInteractor.execute} /w/in /w/tout /w/out`,
|
||||
copyIn: ctx.executeInteractor.copyIn,
|
||||
time: ctxSubtask.subtask.time * 2 * ctx.executeInteractor.time,
|
||||
memory: ctxSubtask.subtask.memory * 2,
|
||||
@@ -103,7 +103,7 @@ export const judge = async (ctx: Context) => {
|
||||
for (const file of ctx.config.user_extra_files) {
|
||||
copyIn[parseFilename(file)] = { src: file };
|
||||
}
|
||||
return compile(ctx.getLang(ctx.lang), ctx.code, 'code', copyIn, ctx.next);
|
||||
return compile(ctx.getLang(ctx.lang), ctx.code, copyIn, ctx.next);
|
||||
})(),
|
||||
(() => {
|
||||
const copyIn = { 'testlib.h': { src: testlibSrc } };
|
||||
@@ -113,7 +113,6 @@ export const judge = async (ctx: Context) => {
|
||||
return compile(
|
||||
ctx.getLang(parseFilename(ctx.config.interactor).split('.')[1].replace('@', '.')),
|
||||
fs.readFileSync(ctx.config.interactor).toString(),
|
||||
'interactor',
|
||||
copyIn,
|
||||
);
|
||||
})(),
|
||||
|
||||
@@ -8,46 +8,32 @@ import signals from '../signals';
|
||||
import { compilerText, parseMemoryMB, parseTimeMS } from '../utils';
|
||||
import { Context } from './interface';
|
||||
|
||||
const failure = (status: number, message?: string) => ({
|
||||
status,
|
||||
score: 0,
|
||||
time_ms: 0,
|
||||
memory_kb: 0,
|
||||
message,
|
||||
});
|
||||
|
||||
export const judge = async (ctx: Context) => {
|
||||
ctx.stat.judge = new Date();
|
||||
ctx.next({ status: STATUS.STATUS_COMPILING });
|
||||
try {
|
||||
ctx.execute = await compile(ctx.getLang(ctx.lang), ctx.code, 'code', {}, ctx.next);
|
||||
ctx.execute = await compile(ctx.getLang(ctx.lang), ctx.code, {}, ctx.next);
|
||||
} catch (e) {
|
||||
if (e instanceof CompileError) {
|
||||
ctx.next({
|
||||
status: STATUS.STATUS_COMPILE_ERROR,
|
||||
case: {
|
||||
status: STATUS.STATUS_COMPILE_ERROR,
|
||||
score: 0,
|
||||
time_ms: 0,
|
||||
memory_kb: 0,
|
||||
message: compilerText(e.stdout, e.stderr),
|
||||
},
|
||||
});
|
||||
ctx.end({
|
||||
status: STATUS.STATUS_COMPILE_ERROR,
|
||||
score: 0,
|
||||
time_ms: 0,
|
||||
memory_kb: 0,
|
||||
case: failure(STATUS.STATUS_COMPILE_ERROR, compilerText(e.stdout, e.stderr)),
|
||||
});
|
||||
ctx.end(failure(STATUS.STATUS_COMPILE_ERROR));
|
||||
} else {
|
||||
ctx.next({
|
||||
status: STATUS.STATUS_SYSTEM_ERROR,
|
||||
case: {
|
||||
status: STATUS.STATUS_SYSTEM_ERROR,
|
||||
score: 0,
|
||||
time_ms: 0,
|
||||
memory_kb: 0,
|
||||
message: `${e.message}\n${JSON.stringify(e.params)}`,
|
||||
},
|
||||
});
|
||||
ctx.end({
|
||||
status: STATUS.STATUS_COMPILE_ERROR,
|
||||
score: 0,
|
||||
time_ms: 0,
|
||||
memory_kb: 0,
|
||||
case: failure(STATUS.STATUS_SYSTEM_ERROR, `${e.message}\n${JSON.stringify(e.params)}`),
|
||||
});
|
||||
ctx.end(failure(STATUS.STATUS_SYSTEM_ERROR));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -62,7 +48,7 @@ export const judge = async (ctx: Context) => {
|
||||
const stdout = path.resolve(ctx.tmpdir, '0.out');
|
||||
const stderr = path.resolve(ctx.tmpdir, '0.err');
|
||||
const res = await run(
|
||||
ctx.execute.execute.replace(/\$\{name\}/g, 'code'),
|
||||
ctx.execute.execute,
|
||||
{
|
||||
stdin: filename ? null : stdin,
|
||||
stdout: filename ? null : stdout,
|
||||
@@ -96,7 +82,7 @@ export const judge = async (ctx: Context) => {
|
||||
status,
|
||||
time_ms: time_usage_ms,
|
||||
memory_kb: memory_usage_kb,
|
||||
message: message.join('\n').substr(0, 102400),
|
||||
message: message.join('\n').substring(0, 102400),
|
||||
},
|
||||
});
|
||||
ctx.stat.done = new Date();
|
||||
|
||||
@@ -59,7 +59,7 @@ function checkStringArray(args: ParseEntry[]): args is string[] {
|
||||
}
|
||||
|
||||
function parseArgs(execute: string): string[] {
|
||||
const args = cmd(execute.replace(/\$\{dir\}/g, '/w'));
|
||||
const args = cmd(execute);
|
||||
if (!checkStringArray(args)) {
|
||||
throw new SystemError(`${execute} contains invalid operator`);
|
||||
}
|
||||
@@ -76,7 +76,7 @@ function proc({
|
||||
env = {},
|
||||
}: Parameter = {}): Cmd {
|
||||
if (!supportOptional) {
|
||||
copyOut = (copyOut as string[]).map((i) => (i.endsWith('?') ? i.substr(0, i.length - 1) : i));
|
||||
copyOut = copyOut.map((i) => (i.endsWith('?') ? i.substring(0, i.length - 1) : i));
|
||||
}
|
||||
const size = parseMemoryMB(getConfig('stdio_size'));
|
||||
const rate = getConfig('rate');
|
||||
|
||||
@@ -134,10 +134,11 @@ async function postInit() {
|
||||
};
|
||||
}
|
||||
|
||||
function getLang(lang: string) {
|
||||
function getLang(lang: string, doThrow = true) {
|
||||
if (setting.langs[lang]) return setting.langs[lang];
|
||||
if (lang === 'cpp' && setting.langs['cc']) return setting.langs['cc'];
|
||||
throw new SystemError('Unsupported language {0}.', [lang]);
|
||||
if (doThrow) throw new SystemError('Unsupported language {0}.', [lang]);
|
||||
return null;
|
||||
}
|
||||
|
||||
class JudgeTask {
|
||||
|
||||
@@ -35,10 +35,10 @@ int main(){
|
||||
},
|
||||
end: () => { },
|
||||
getLang: () => ({
|
||||
compile: '/usr/bin/g++ -Wall -std=c++14 -o foo.cc foo.cc -lm',
|
||||
execute: 'foo',
|
||||
compile: '/usr/bin/g++ -Wall -std=c++14 -o foo foo.cc -lm',
|
||||
execute: '/w/foo',
|
||||
code_file: 'foo.cc',
|
||||
highlight: 'cpp astyle-c',
|
||||
highlight: 'cpp',
|
||||
monaco: 'cpp',
|
||||
display: 'C++',
|
||||
time_limit_rate: 1,
|
||||
|
||||
@@ -22,7 +22,6 @@ const encrypt = (algorithm: string, content: crypto.BinaryLike) => {
|
||||
return hash.digest('hex');
|
||||
};
|
||||
|
||||
export const sha1 = (content: string) => encrypt('sha1', content);
|
||||
export const md5 = (content: string) => encrypt('md5', content);
|
||||
|
||||
export class Queue<T> extends EventEmitter {
|
||||
@@ -69,26 +68,11 @@ export namespace Lock {
|
||||
|
||||
export function compilerText(stdout: string, stderr: string) {
|
||||
const ret = [];
|
||||
if (!EMPTY_STR.test(stdout)) ret.push(stdout.substr(0, 1024 * 1024));
|
||||
if (!EMPTY_STR.test(stderr)) ret.push(stderr.substr(0, 1024 * 1024));
|
||||
if (!EMPTY_STR.test(stdout)) ret.push(stdout.substring(0, 1024 * 1024));
|
||||
if (!EMPTY_STR.test(stderr)) ret.push(stderr.substring(0, 1024 * 1024));
|
||||
return ret.join('\n');
|
||||
}
|
||||
|
||||
export function copyInDir(dir: string) {
|
||||
const files = {};
|
||||
if (fs.existsSync(dir)) {
|
||||
fs.readdirSync(dir).forEach((f1) => {
|
||||
const p1 = `${dir}/${f1}`;
|
||||
if (fs.statSync(p1).isDirectory()) {
|
||||
fs.readdirSync(p1).forEach((f2) => {
|
||||
files[`${f1}/${f2}`] = { src: `${dir}/${f1}/${f2}` };
|
||||
});
|
||||
} else files[f1] = { src: `${dir}/${f1}` };
|
||||
});
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
export function restrictFile(p: string) {
|
||||
if (!p) return '/';
|
||||
if (p[0] === '/') p = '';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hydrooj",
|
||||
"version": "3.4.31",
|
||||
"version": "3.5.0",
|
||||
"bin": "bin/hydrooj.js",
|
||||
"main": "src/loader",
|
||||
"module": "src/loader",
|
||||
|
||||
@@ -32,33 +32,33 @@ langs:
|
||||
target: Compiler output file
|
||||
display: Display name
|
||||
c:
|
||||
compile: /usr/bin/gcc -Wall --std=c99 -o ${name} foo.c -lm
|
||||
highlight: c astyle-c
|
||||
compile: /usr/bin/gcc -Wall --std=c99 -o foo foo.c -lm
|
||||
highlight: c
|
||||
monaco: cpp
|
||||
display: C
|
||||
cc:
|
||||
compile: /usr/bin/g++ -Wall -std=c++14 -o ${name} foo.cc -lm
|
||||
compile: /usr/bin/g++ -Wall -std=c++14 -o foo foo.cc -lm
|
||||
code_file: foo.cc
|
||||
highlight: cpp astyle-c
|
||||
highlight: cpp
|
||||
monaco: cpp
|
||||
display: C++
|
||||
cc.std98:
|
||||
compile: /usr/bin/g++ -Wall -std=c++98 -o ${name} foo.cc -lm
|
||||
compile: /usr/bin/g++ -Wall -std=c++98 -o foo foo.cc -lm
|
||||
display: C++ 98
|
||||
cc.std11:
|
||||
compile: /usr/bin/g++ -Wall -std=c++11 -o ${name} foo.cc -lm
|
||||
compile: /usr/bin/g++ -Wall -std=c++11 -o foo foo.cc -lm
|
||||
display: C++ 11
|
||||
cc.std14:
|
||||
display: C++ 14
|
||||
cc.std17:
|
||||
compile: /usr/bin/g++ -Wall -std=c++17 -o ${name} foo.cc -lm
|
||||
compile: /usr/bin/g++ -Wall -std=c++17 -o foo foo.cc -lm
|
||||
display: C++ 17
|
||||
pas:
|
||||
compile: /usr/bin/fpc -O2 -o${dir}/${name} foo.pas
|
||||
compile: /usr/bin/fpc -O2 -o/w/foo foo.pas
|
||||
highlight: pascal
|
||||
display: Pascal
|
||||
java:
|
||||
compile: /usr/bin/bash -c "javac -d ${dir} -encoding utf8 ./Main.java && jar cvf Main.jar *.class >/dev/null"
|
||||
compile: /usr/bin/bash -c "javac -d /w -encoding utf8 ./Main.java && jar cvf Main.jar *.class >/dev/null"
|
||||
code_file: Main.java
|
||||
target: Main.jar
|
||||
execute: /usr/bin/java -cp Main.jar Main
|
||||
@@ -67,46 +67,42 @@ langs:
|
||||
monaco: java
|
||||
display: Java
|
||||
py:
|
||||
compile: /usr/bin/python -c "import py_compile; py_compile.compile('${dir}/foo.py', '${dir}/${name}', doraise=True)"
|
||||
compile: /usr/bin/python -c "import py_compile; py_compile.compile('/w/foo.py', '/w/foo', doraise=True)"
|
||||
code_file: foo.py
|
||||
execute: /usr/bin/python ${name}
|
||||
execute: /usr/bin/python foo
|
||||
highlight: python
|
||||
display: Python
|
||||
py.py2:
|
||||
display: Python 2
|
||||
py.py3:
|
||||
compile: /usr/bin/python3 -c "import py_compile; py_compile.compile('${dir}/foo.py', '${dir}/${name}', doraise=True)"
|
||||
execute: /usr/bin/python3 ${name}
|
||||
compile: /usr/bin/python3 -c "import py_compile; py_compile.compile('/w/foo.py', '/w/foo', doraise=True)"
|
||||
execute: /usr/bin/python3 foo
|
||||
display: Python 3
|
||||
php:
|
||||
execute: /usr/bin/php foo.php
|
||||
display: PHP
|
||||
rs:
|
||||
compile: /usr/bin/rustc -O -o ${dir}/${name} ${dir}/foo.rs
|
||||
compile: /usr/bin/rustc -O -o /w/foo /w/foo.rs
|
||||
highlight: rust
|
||||
display: Rust
|
||||
hs:
|
||||
compile: /usr/bin/ghc -O -outputdir /tmp -o ${name} foo.hs
|
||||
compile: /usr/bin/ghc -O -outputdir /tmp -o foo foo.hs
|
||||
highlight: haskell
|
||||
display: Haskell
|
||||
js:
|
||||
execute: /usr/bin/jsc ${dir}/foo.js
|
||||
execute: /usr/bin/jsc /w/foo.js
|
||||
highlight: javascript
|
||||
display: Javascript (JSC)
|
||||
go:
|
||||
compile: /usr/bin/go build -o ${name} foo.go
|
||||
compile: /usr/bin/go build -o foo foo.go
|
||||
display: Golang
|
||||
rb:
|
||||
execute: /usr/bin/ruby foo.rb
|
||||
highlight: ruby
|
||||
display: Ruby
|
||||
cs:
|
||||
compile: /usr/bin/mcs -optimize+ -out:${dir}/${name} ${dir}/foo.cs
|
||||
execute: /usr/bin/mono ${name}
|
||||
highlight: csharp astyle-cs
|
||||
compile: /usr/bin/mcs -optimize+ -out:/w/foo /w/foo.cs
|
||||
execute: /usr/bin/mono foo
|
||||
highlight: csharp
|
||||
monaco: csharp
|
||||
display: Csharp
|
||||
jl:
|
||||
execute: /usr/bin/julia ${dir}/foo.jl
|
||||
highlight: julia
|
||||
display: Julia
|
||||
display: 'C#'
|
||||
@@ -72,6 +72,7 @@ class RecordModel {
|
||||
pdoc = await problem.get(pdoc.reference.domainId, pdoc.reference.pid);
|
||||
if (!pdoc) throw new ProblemNotFoundError(rdoc.domainId, rdoc.pid);
|
||||
}
|
||||
(config as any).problemOwner = pdoc.owner;
|
||||
source = `${pdoc.domainId}/${pdoc.docId}`;
|
||||
data = pdoc.data;
|
||||
if (typeof pdoc.config === 'string') throw new Error(pdoc.config);
|
||||
|
||||
@@ -683,6 +683,10 @@ const scripts: UpgradeScript[] = [
|
||||
await TaskModel.deleteMany({ type: 'schedule', subType: 'contest.problemHide' });
|
||||
return true;
|
||||
},
|
||||
async function _59_60() {
|
||||
const langs = await system.get('hydrooj.langs');
|
||||
await system.set('hydrooj.langs', langs.replace(/\$\{dir\}/g, '/w').replace(/\$\{name\}/g, 'foo'));
|
||||
},
|
||||
];
|
||||
|
||||
export default scripts;
|
||||
Reference in new issue
Block a user