core: update judge config

This commit is contained in:
undefined committed 2022-02-25 12:09:32 +08:00
1 parent d13876a5bc
commit a2004056ac
22 files changed
+100 -245

No files matched your search

+1 -1
View File
@@ -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",
+2 -2
View File
@@ -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]);
}
+10 -2
View File
@@ -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);
}
+5 -5
View File
@@ -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,
+3 -3
View File
@@ -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 });
+8 -3
View File
@@ -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>) {
+2 -2
View File
@@ -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';
+2
View File
@@ -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);
}
+1
View File
@@ -14,6 +14,7 @@ export interface CompileErrorInfo {
}
export interface CheckConfig {
execute: string;
checker_type: string;
input: CopyInFile;
output: CopyInFile;
+10 -9
View File
@@ -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 = {};
-132
View File
@@ -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 -2
View File
@@ -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> }>;
+3 -4
View File
@@ -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,
);
})(),
+15 -29
View File
@@ -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();
+2 -2
View File
@@ -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');
+3 -2
View File
@@ -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 {
+3 -3
View File
@@ -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,
+2 -18
View File
@@ -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 -1
View File
@@ -1,6 +1,6 @@
{
"name": "hydrooj",
"version": "3.4.31",
"version": "3.5.0",
"bin": "bin/hydrooj.js",
"main": "src/loader",
"module": "src/loader",
+21 -25
View File
@@ -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#'
+1
View File
@@ -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);
+4
View File
@@ -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;