diff --git a/README.md b/README.md index 1f105f058..3dbc3bc5e 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,11 @@ Hydro 用户群:1085853538

更新日志(点击展开)

+## Unreleased + +- judge: breaking: 不再支持在 checker 等的编译阶段读取选手代码 + + ## Hydro 4.19.0 / UI 4.57.0 - core&ui&judge: 添加通信题支持 diff --git a/packages/hydrojudge/src/compile.ts b/packages/hydrojudge/src/compile.ts index 1e9f525f8..142a6c02a 100644 --- a/packages/hydrojudge/src/compile.ts +++ b/packages/hydrojudge/src/compile.ts @@ -1,7 +1,6 @@ import { LangConfig } from '@hydrooj/utils/lib/lang'; import { STATUS } from '@hydrooj/utils/lib/status'; -import { findFileSync } from '@hydrooj/utils/lib/utils'; -import { CompileError, FormatError } from './error'; +import { CompileError } from './error'; import { Execute } from './interface'; import { CopyIn, CopyInFile, del, runQueued, @@ -46,25 +45,3 @@ export default async function compile( 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); -} diff --git a/packages/hydrojudge/src/hosts/vj4.ts b/packages/hydrojudge/src/hosts/vj4.ts index 9dc449d44..b666789b6 100644 --- a/packages/hydrojudge/src/hosts/vj4.ts +++ b/packages/hydrojudge/src/hosts/vj4.ts @@ -26,7 +26,7 @@ export default class VJ4 implements Session { progress = 0; ws: WebSocket; - async fetchFile(): Promise { + async fetchFile(): Promise { throw new Error('not implemented'); } diff --git a/packages/hydrojudge/src/task.ts b/packages/hydrojudge/src/task.ts index d3710b4b6..5c432dfa1 100644 --- a/packages/hydrojudge/src/task.ts +++ b/packages/hydrojudge/src/task.ts @@ -1,12 +1,12 @@ import { basename, join } from 'path'; -import { fs } from '@hydrooj/utils'; +import { findFileSync, fs } from '@hydrooj/utils'; import { STATUS } from '@hydrooj/utils/lib/status'; import type { - FileInfo, JudgeMeta, JudgeResultBody, TestCase, + CompilableSource, FileInfo, JudgeMeta, JudgeResultBody, TestCase, } from 'hydrooj'; import readCases from './cases'; import checkers from './checkers'; -import compile, { compileLocalFile } from './compile'; +import compile from './compile'; import { getConfig } from './config'; import { CompileError, FormatError } from './error'; import { @@ -19,6 +19,10 @@ import { compilerText, Lock, md5 } from './utils'; const logger = new Logger('judge'); +const testlibFile = { + src: findFileSync('@hydrooj/hydrojudge/vendor/testlib/testlib.h'), +}; + export class JudgeTask { stat: Record = Object.create(null); source: string; @@ -93,6 +97,8 @@ export class JudgeTask { } 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}`; await Lock.acquire(lockKey); const filePath = join(getConfig('cache_dir'), lockKey); @@ -165,19 +171,36 @@ export class JudgeTask { 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' && !checkers[checkerType]) throw new FormatError('Unknown checker type {0}.', [checkerType]); const withTestlib = type !== 'std' && (type !== 'checker' || checkerType === 'testlib'); const extra = type === 'std' ? this.config.user_extra_files : this.config.judge_extra_files; const copyIn = { - user_code: this.code, ...Object.fromEntries( (extra || []).map((i) => [basename(i), { src: i }]), ), + ...(withTestlib ? { testlib: testlibFile } : {}), } as CopyIn; + let [file, langId] = typeof source === 'string' ? [source, 'auto'] : [source.file, source.lang]; 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); return result; }