mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
judge: allow override language
This commit is contained in:
1 parent
cac362121d
commit
100ccf718f
4 files changed
+36
-31
No files matched your search
@@ -111,6 +111,11 @@ Hydro 用户群:1085853538
|
|||||||
<details>
|
<details>
|
||||||
<summary><h2>更新日志(点击展开)</h2></summary>
|
<summary><h2>更新日志(点击展开)</h2></summary>
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
- judge: breaking: 不再支持在 checker 等的编译阶段读取选手代码
|
||||||
|
|
||||||
|
|
||||||
## Hydro 4.19.0 / UI 4.57.0
|
## Hydro 4.19.0 / UI 4.57.0
|
||||||
|
|
||||||
- core&ui&judge: 添加通信题支持
|
- core&ui&judge: 添加通信题支持
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { LangConfig } from '@hydrooj/utils/lib/lang';
|
import { LangConfig } from '@hydrooj/utils/lib/lang';
|
||||||
import { STATUS } from '@hydrooj/utils/lib/status';
|
import { STATUS } from '@hydrooj/utils/lib/status';
|
||||||
import { findFileSync } from '@hydrooj/utils/lib/utils';
|
import { CompileError } from './error';
|
||||||
import { CompileError, FormatError } from './error';
|
|
||||||
import { Execute } from './interface';
|
import { Execute } from './interface';
|
||||||
import {
|
import {
|
||||||
CopyIn, CopyInFile, del, runQueued,
|
CopyIn, CopyInFile, del, runQueued,
|
||||||
@@ -46,25 +45,3 @@ export default async function compile(
|
|||||||
clean: () => Promise.resolve(null),
|
clean: () => Promise.resolve(null),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const testlibFile = {
|
|
||||||
src: findFileSync('@hydrooj/hydrojudge/vendor/testlib/testlib.h'),
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function compileLocalFile(
|
|
||||||
src: string, type: 'checker' | 'validator' | 'interactor' | 'generator' | 'manager' | 'std',
|
|
||||||
getLang, copyIn: CopyIn, withTestlib = true, next?: any,
|
|
||||||
) {
|
|
||||||
const s = src.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 FormatError(`Unknown ${type} language.`);
|
|
||||||
if (withTestlib) copyIn = { ...copyIn, 'testlib.h': testlibFile };
|
|
||||||
// TODO cache compiled binary
|
|
||||||
return await compile(lang, { src }, copyIn, next);
|
|
||||||
}
|
|
||||||
@@ -26,7 +26,7 @@ export default class VJ4 implements Session {
|
|||||||
progress = 0;
|
progress = 0;
|
||||||
ws: WebSocket;
|
ws: WebSocket;
|
||||||
|
|
||||||
async fetchFile(): Promise<string> {
|
async fetchFile(): Promise<any> {
|
||||||
throw new Error('not implemented');
|
throw new Error('not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { basename, join } from 'path';
|
import { basename, join } from 'path';
|
||||||
import { fs } from '@hydrooj/utils';
|
import { findFileSync, fs } from '@hydrooj/utils';
|
||||||
import { STATUS } from '@hydrooj/utils/lib/status';
|
import { STATUS } from '@hydrooj/utils/lib/status';
|
||||||
import type {
|
import type {
|
||||||
FileInfo, JudgeMeta, JudgeResultBody, TestCase,
|
CompilableSource, FileInfo, JudgeMeta, JudgeResultBody, TestCase,
|
||||||
} from 'hydrooj';
|
} from 'hydrooj';
|
||||||
import readCases from './cases';
|
import readCases from './cases';
|
||||||
import checkers from './checkers';
|
import checkers from './checkers';
|
||||||
import compile, { compileLocalFile } from './compile';
|
import compile from './compile';
|
||||||
import { getConfig } from './config';
|
import { getConfig } from './config';
|
||||||
import { CompileError, FormatError } from './error';
|
import { CompileError, FormatError } from './error';
|
||||||
import {
|
import {
|
||||||
@@ -19,6 +19,10 @@ import { compilerText, Lock, md5 } from './utils';
|
|||||||
|
|
||||||
const logger = new Logger('judge');
|
const logger = new Logger('judge');
|
||||||
|
|
||||||
|
const testlibFile = {
|
||||||
|
src: findFileSync('@hydrooj/hydrojudge/vendor/testlib/testlib.h'),
|
||||||
|
};
|
||||||
|
|
||||||
export class JudgeTask {
|
export class JudgeTask {
|
||||||
stat: Record<string, Date> = Object.create(null);
|
stat: Record<string, Date> = Object.create(null);
|
||||||
source: string;
|
source: string;
|
||||||
@@ -93,6 +97,8 @@ export class JudgeTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async cacheOpen(source: string, files: FileInfo[]) {
|
async cacheOpen(source: string, files: FileInfo[]) {
|
||||||
|
// Backward compatibility for vj4
|
||||||
|
if ((this.session as any).cacheOpen) return (this.session as any).cacheOpen(source, files);
|
||||||
const lockKey = `${this.session.config?.host || 'local'}/${source}`;
|
const lockKey = `${this.session.config?.host || 'local'}/${source}`;
|
||||||
await Lock.acquire(lockKey);
|
await Lock.acquire(lockKey);
|
||||||
const filePath = join(getConfig('cache_dir'), lockKey);
|
const filePath = join(getConfig('cache_dir'), lockKey);
|
||||||
@@ -165,19 +171,36 @@ export class JudgeTask {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async compileLocalFile(type: 'interactor' | 'validator' | 'checker' | 'generator' | 'manager' | 'std', file: string, checkerType?: string) {
|
async compileLocalFile(
|
||||||
|
type: 'interactor' | 'validator' | 'checker' | 'generator' | 'manager' | 'std',
|
||||||
|
source: CompilableSource,
|
||||||
|
checkerType?: string,
|
||||||
|
) {
|
||||||
if (type === 'checker' && ['default', 'strict'].includes(checkerType)) return { execute: '', copyIn: {}, clean: () => Promise.resolve(null) };
|
if (type === 'checker' && ['default', 'strict'].includes(checkerType)) return { execute: '', copyIn: {}, clean: () => Promise.resolve(null) };
|
||||||
if (type === 'checker' && !checkers[checkerType]) throw new FormatError('Unknown checker type {0}.', [checkerType]);
|
if (type === 'checker' && !checkers[checkerType]) throw new FormatError('Unknown checker type {0}.', [checkerType]);
|
||||||
const withTestlib = type !== 'std' && (type !== 'checker' || checkerType === 'testlib');
|
const withTestlib = type !== 'std' && (type !== 'checker' || checkerType === 'testlib');
|
||||||
const extra = type === 'std' ? this.config.user_extra_files : this.config.judge_extra_files;
|
const extra = type === 'std' ? this.config.user_extra_files : this.config.judge_extra_files;
|
||||||
const copyIn = {
|
const copyIn = {
|
||||||
user_code: this.code,
|
|
||||||
...Object.fromEntries(
|
...Object.fromEntries(
|
||||||
(extra || []).map((i) => [basename(i), { src: i }]),
|
(extra || []).map((i) => [basename(i), { src: i }]),
|
||||||
),
|
),
|
||||||
|
...(withTestlib ? { testlib: testlibFile } : {}),
|
||||||
} as CopyIn;
|
} as CopyIn;
|
||||||
|
let [file, langId] = typeof source === 'string' ? [source, 'auto'] : [source.file, source.lang];
|
||||||
if (!file.startsWith('/')) file = join(this.folder, file);
|
if (!file.startsWith('/')) file = join(this.folder, file);
|
||||||
const result = await compileLocalFile(file, type, this.session.getLang, copyIn, withTestlib, this.next);
|
let lang;
|
||||||
|
if (langId === 'auto') {
|
||||||
|
const s = file.replace('@', '.').split('.');
|
||||||
|
langId = s.pop();
|
||||||
|
while (s.length) {
|
||||||
|
lang = this.session.getLang(langId);
|
||||||
|
if (lang) break;
|
||||||
|
langId = `${s.pop()}.${langId}`;
|
||||||
|
}
|
||||||
|
} else lang = this.session.getLang(langId);
|
||||||
|
if (!lang) throw new FormatError(`Unknown ${type} language.`);
|
||||||
|
// TODO cache compiled binary
|
||||||
|
const result = await compile(lang, { src: file }, copyIn, this.next);
|
||||||
this.clean.push(result.clean);
|
this.clean.push(result.clean);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user