From 5e113d9c7efa1f5abc96cdaf8732bae41b850634 Mon Sep 17 00:00:00 2001 From: undefined Date: Sat, 3 Sep 2022 14:56:12 +0800 Subject: [PATCH] judge: use compileInteractor and per file cleanup --- packages/hydrojudge/src/compile.ts | 9 ++++- packages/hydrojudge/src/judge/default.ts | 10 +++-- packages/hydrojudge/src/judge/interactive.ts | 40 +++++++++----------- packages/hydrooj/bin/commands.ts | 17 ++++++++- packages/vjudge/src/model.ts | 3 ++ 5 files changed, 52 insertions(+), 27 deletions(-) diff --git a/packages/hydrojudge/src/compile.ts b/packages/hydrojudge/src/compile.ts index 3254e1e4f..5858f4d9d 100644 --- a/packages/hydrojudge/src/compile.ts +++ b/packages/hydrojudge/src/compile.ts @@ -43,7 +43,7 @@ export default async function compile( } const testlibFile = { - src: findFileSync('@hydrooj/hydrojudge/vendor/testlib/testlib.h') + src: findFileSync('@hydrooj/hydrojudge/vendor/testlib/testlib.h'), }; const guessLanguage = (filename: string, getLang: Function) => { @@ -70,6 +70,13 @@ export async function compileChecker(getLang: Function, checkerType: string, che return await compile(lang, { src: checker }, copyIn); } +export async function compileInteractor(getLang: Function, interactor: string, copyIn: any): Promise { + const lang = guessLanguage(interactor, getLang); + if (!lang) throw new FormatError('Unknown interactor language.'); + // TODO cache compiled checker + return await compile(lang, { src: interactor }, { ...copyIn, 'testlib.h': testlibFile }); +} + export async function compileValidator(getLang: Function, validator: string, copyIn: any): Promise { const lang = guessLanguage(validator, getLang); if (!lang) throw new FormatError('Unknown validator language.'); diff --git a/packages/hydrojudge/src/judge/default.ts b/packages/hydrojudge/src/judge/default.ts index d9b2dca2f..ffe15040d 100644 --- a/packages/hydrojudge/src/judge/default.ts +++ b/packages/hydrojudge/src/judge/default.ts @@ -3,6 +3,7 @@ import { STATUS } from '@hydrooj/utils/lib/status'; import checkers from '../checkers'; import compile, { compileChecker } from '../compile'; import { runFlow } from '../flow'; +import { Execute } from '../interface'; import { Logger } from '../log'; import { CmdFile, del, run } from '../sandbox'; import signals from '../signals'; @@ -121,6 +122,10 @@ function judgeCase(c: NormalizedCase, sid: string) { export const judge = async (ctx: Context) => await runFlow(ctx, { compile: async () => { + const markCleanup = (i: Execute) => { + ctx.clean.push(i.clean); + return i; + }; [ctx.execute, ctx.checker] = await Promise.all([ compile( ctx.session.getLang(ctx.lang), ctx.code, @@ -128,7 +133,7 @@ export const judge = async (ctx: Context) => await runFlow(ctx, { (ctx.config.user_extra_files || []).map((i) => [i.split('/').pop(), { src: i }]), ), ctx.next, - ), + ).then(markCleanup), compileChecker( ctx.session.getLang, ctx.config.checker_type, @@ -139,9 +144,8 @@ export const judge = async (ctx: Context) => await runFlow(ctx, { (ctx.config.judge_extra_files || []).map((i) => [basename(i), { src: i }]), ), }, - ), + ).then(markCleanup), ]); - ctx.clean.push(ctx.execute.clean, ctx.checker.clean); }, judgeCase, }); diff --git a/packages/hydrojudge/src/judge/interactive.ts b/packages/hydrojudge/src/judge/interactive.ts index 73c06d1f2..dbe7a0a63 100644 --- a/packages/hydrojudge/src/judge/interactive.ts +++ b/packages/hydrojudge/src/judge/interactive.ts @@ -1,7 +1,8 @@ import { basename } from 'path'; import { STATUS } from '@hydrooj/utils/lib/status'; -import compile from '../compile'; +import compile, { compileInteractor } from '../compile'; import { runFlow } from '../flow'; +import { Execute } from '../interface'; import { runPiped } from '../sandbox'; import signals from '../signals'; import { parse } from '../testlib'; @@ -76,28 +77,23 @@ function judgeCase(c: NormalizedCase) { export const judge = async (ctx: Context) => await runFlow(ctx, { compile: async () => { + const markCleanup = (i: Execute) => { + ctx.clean.push(i.clean); + return i; + }; + const userExtraFiles = Object.fromEntries( + (ctx.config.user_extra_files || []).map((i) => [basename(i), { src: i }]), + ); + const interactorFiles = { + 'testlib.h': { src: testlibSrc }, + user_code: ctx.code, + }; + for (const file of ctx.config.judge_extra_files) { + interactorFiles[basename(file)] = { src: file }; + } [ctx.executeUser, ctx.executeInteractor] = await Promise.all([ - (() => { - const copyIn = {}; - for (const file of ctx.config.user_extra_files) { - copyIn[basename(file)] = { src: file }; - } - return compile(ctx.session.getLang(ctx.lang), ctx.code, copyIn, ctx.next); - })(), - (() => { - const copyIn = { - 'testlib.h': { src: testlibSrc }, - user_code: ctx.code, - }; - for (const file of ctx.config.judge_extra_files) { - copyIn[basename(file)] = { src: file }; - } - return compile( - ctx.session.getLang(basename(ctx.config.interactor).split('.')[1].replace('@', '.')), - { src: ctx.config.interactor }, - copyIn, - ); - })(), + compile(ctx.session.getLang(ctx.lang), ctx.code, userExtraFiles, ctx.next).then(markCleanup), + compileInteractor(ctx.session.getLang, ctx.config.interactor, interactorFiles).then(markCleanup), ]); ctx.clean.push(ctx.executeUser.clean, ctx.executeInteractor.clean); }, diff --git a/packages/hydrooj/bin/commands.ts b/packages/hydrooj/bin/commands.ts index ab74dd0c0..a5306fffb 100644 --- a/packages/hydrooj/bin/commands.ts +++ b/packages/hydrooj/bin/commands.ts @@ -1,10 +1,16 @@ -import child from 'child_process'; +import child, { execSync } from 'child_process'; import os from 'os'; import path from 'path'; import cac from 'cac'; import fs from 'fs-extra'; const argv = cac().parse(); +let isGlobal = null; +try { + isGlobal = __dirname.startsWith(execSync('yarn global dir').toString().trim()); +} catch (e) { + // yarn 2 does not support global dir +} const exec = (...args) => { console.log('Executing: ', args[0], args[1].join(' ')); @@ -115,6 +121,15 @@ if (!argv.args[0] || argv.args[0] === 'cli') { console.log('Current Addons: ', addons); fs.writeFileSync(addonPath, JSON.stringify(addons, null, 2)); }); + cli.command('install [package]').action((name) => { + if (!isGlobal) { + console.warn('This is not a global installation, unable to install.'); + return; + } + // TODO support install from tarball + child.execSync(`yarn global install '${name}'`, { stdio: 'inherit' }); + child.execSync(`hydrooj addon add '${name}'`); + }); cli.help(); cli.parse(); if (!cli.matchedCommand) console.log('Unknown command.'); diff --git a/packages/vjudge/src/model.ts b/packages/vjudge/src/model.ts index ade04afaf..d37d35519 100644 --- a/packages/vjudge/src/model.ts +++ b/packages/vjudge/src/model.ts @@ -1,5 +1,6 @@ /* eslint-disable no-await-in-loop */ import { sleep } from '@hydrooj/utils/lib/utils'; +import { writeFileSync } from 'fs-extra'; import * as Judge from 'hydrooj/src/handler/judge'; import { Logger } from 'hydrooj/src/logger'; import { STATUS } from 'hydrooj/src/model/builtin'; @@ -55,6 +56,8 @@ class Service { async sync(domainId: string, resync = false, list: string) { let page = 1; + const res = await this.api.getProblem('P1721D', {}); + writeFileSync('a.md', res.content); let pids = await this.api.listProblem(page, resync, list); while (pids.length) { logger.info(`${domainId}: Syncing page ${page}`);