mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-19 09:38:19 +08:00
core&judge: probe compiler versions
This commit is contained in:
6 files changed
+94
-9
No files matched your search
@@ -0,0 +1,18 @@
|
||||
import { LangConfig } from '@hydrooj/utils/lib/lang';
|
||||
import { runQueued } from './sandbox';
|
||||
|
||||
export async function compilerVersions(langs: Record<string, LangConfig>) {
|
||||
const result = {};
|
||||
for (const lang in langs) {
|
||||
const version = langs[lang].version;
|
||||
if (!version) continue;
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const res = await runQueued(version, {
|
||||
copyIn: {},
|
||||
time: 10000,
|
||||
memory: 256 * 1024 * 1024,
|
||||
}, 5);
|
||||
result[lang] = `${res.stdout}\n${res.stderr}`.trim();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -2,10 +2,13 @@
|
||||
/* eslint-disable no-await-in-loop */
|
||||
import path from 'path';
|
||||
import { fs } from '@hydrooj/utils';
|
||||
import * as sysinfo from '@hydrooj/utils/lib/sysinfo';
|
||||
import {
|
||||
JudgeHandler, JudgeResultBody, ObjectId, RecordModel, SettingModel,
|
||||
StorageModel, SystemModel, TaskModel,
|
||||
db, JudgeHandler, JudgeResultBody, ObjectId, RecordModel,
|
||||
SettingModel, StorageModel, SystemModel, TaskModel,
|
||||
} from 'hydrooj';
|
||||
import { langs } from 'hydrooj/src/model/setting';
|
||||
import { compilerVersions } from '../compiler';
|
||||
import { getConfig } from '../config';
|
||||
import { FormatError, SystemError } from '../error';
|
||||
import { Context } from '../judge/interface';
|
||||
@@ -82,6 +85,7 @@ export async function postInit(ctx) {
|
||||
c.check.addChecker('Judge', (_ctx, log, warn, error) => versionCheck(warn, error));
|
||||
});
|
||||
await fs.ensureDir(getConfig('tmp_dir'));
|
||||
const info = await sysinfo.get();
|
||||
const handle = async (t) => {
|
||||
const rdoc = await RecordModel.get(t.domainId, t.rid);
|
||||
if (!rdoc) {
|
||||
@@ -92,9 +96,19 @@ export async function postInit(ctx) {
|
||||
};
|
||||
const parallelism = Math.max(getConfig('parallelism'), 2);
|
||||
const taskConsumer = TaskModel.consume({ type: 'judge' }, handle, true, parallelism);
|
||||
function collectCompilerInfo() {
|
||||
const coll = db.collection('status');
|
||||
compilerVersions(langs).then((compilers) => coll.updateOne(
|
||||
{ mid: info.mid, type: 'judge' },
|
||||
{ $set: { compilers } },
|
||||
{ upsert: true },
|
||||
)).catch((e) => logger.error(e));
|
||||
}
|
||||
ctx.on('system/setting', () => {
|
||||
taskConsumer.setConcurrency(Math.max(getConfig('parallelism'), 2));
|
||||
collectCompilerInfo();
|
||||
});
|
||||
collectCompilerInfo();
|
||||
TaskModel.consume({ type: 'judge', priority: { $gt: -50 } }, handle);
|
||||
TaskModel.consume({ type: 'generate' }, handle);
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { fs, pipeRequest } from '@hydrooj/utils';
|
||||
import { LangConfig } from '@hydrooj/utils/lib/lang';
|
||||
import * as sysinfo from '@hydrooj/utils/lib/sysinfo';
|
||||
import type { JudgeResultBody } from 'hydrooj';
|
||||
import { compilerVersions } from '../compiler';
|
||||
import { getConfig } from '../config';
|
||||
import { FormatError, SystemError } from '../error';
|
||||
import { Session } from '../interface';
|
||||
@@ -173,13 +174,19 @@ export default class Hydro implements Session {
|
||||
const content = Object.keys(config).length
|
||||
? JSON.stringify({ key: 'config', ...config })
|
||||
: '{"key":"ping"}';
|
||||
let compilers = {};
|
||||
this.ws.on('message', (data) => {
|
||||
if (data.toString() === 'ping') {
|
||||
this.ws.send('pong');
|
||||
return;
|
||||
}
|
||||
const request = JSON.parse(data.toString());
|
||||
if (request.language) this.language = request.language;
|
||||
if (request.language) {
|
||||
this.language = request.language;
|
||||
compilerVersions(this.language).then((res) => {
|
||||
compilers = res;
|
||||
});
|
||||
}
|
||||
if (request.task) queue.add(() => new JudgeTask(this, request.task).handle().catch((e) => log.error(e)));
|
||||
});
|
||||
this.ws.on('close', (data, reason) => {
|
||||
@@ -196,10 +203,10 @@ export default class Hydro implements Session {
|
||||
this.ws.send('{"key":"start"}');
|
||||
if (!this.config.noStatus) {
|
||||
const info = await sysinfo.get();
|
||||
this.ws.send(JSON.stringify({ key: 'status', info }));
|
||||
this.ws.send(JSON.stringify({ key: 'status', info: { ...info, compilers } }));
|
||||
setInterval(async () => {
|
||||
const [mid, inf] = await sysinfo.update();
|
||||
this.ws.send(JSON.stringify({ key: 'status', info: { mid, ...inf } }));
|
||||
this.ws.send(JSON.stringify({ key: 'status', info: { mid, ...inf, compilers } }));
|
||||
}, 1200000);
|
||||
}
|
||||
resolve(null);
|
||||
|
||||
@@ -23,12 +23,12 @@ langs:
|
||||
- ~ All keys starting with _ will be ignored
|
||||
- ~ Entries named like [foo], [foo].[bar] [foo].[baz]
|
||||
- will be merged into one category.
|
||||
- ~ A entry named [foo].[bar] will inhert all options
|
||||
- ~ A entry named [foo].[bar] will inhert all options
|
||||
- defined in entry [foo] if not overwritten
|
||||
- ~ code_file option defaults to foo.[name]
|
||||
- ~ highlight option defaults to [name]
|
||||
- ~ if highlight option was set, monaco option defaults
|
||||
- to [highlight], otherwise defaults to [name]
|
||||
- to [highlight], otherwise defaults to [name]
|
||||
- ~ Compiling be be ignored if compile option wasn't set
|
||||
- ~ Key marked with a ? means the option is optional
|
||||
- (name):
|
||||
@@ -49,11 +49,13 @@ langs:
|
||||
code_file: foo.sh
|
||||
execute: /bin/bash foo.sh
|
||||
highlight: bash
|
||||
version: /bin/bash --version
|
||||
c:
|
||||
compile: /usr/bin/gcc -Wall --std=c99 -o foo foo.c -lm
|
||||
highlight: c
|
||||
monaco: c
|
||||
display: C
|
||||
version: /usr/bin/gcc --version
|
||||
cc:
|
||||
compile: /usr/bin/g++ -Wall -std=c++14 -o foo foo.cc -lm -I/include
|
||||
code_file: foo.cc
|
||||
@@ -62,6 +64,7 @@ langs:
|
||||
display: C++
|
||||
address_space_limit: true
|
||||
process_limit: 1
|
||||
version: /usr/bin/g++ --version
|
||||
cc.cc98:
|
||||
compile: /usr/bin/g++ -Wall -std=c++98 -o foo foo.cc -lm -I/include
|
||||
display: C++98
|
||||
@@ -95,6 +98,7 @@ langs:
|
||||
compile: /usr/bin/fpc -O2 -o/w/foo foo.pas
|
||||
highlight: pascal
|
||||
display: Pascal
|
||||
version: /usr/bin/fpc -iW
|
||||
java:
|
||||
compile: /usr/bin/bash -c "javac -d /w -encoding utf8 ./Main.java && jar cvf Main.jar *.class >/dev/null"
|
||||
code_file: Main.java
|
||||
@@ -105,6 +109,7 @@ langs:
|
||||
monaco: java
|
||||
display: Java
|
||||
compile_time_limit: 30000
|
||||
version: /usr/bin/javac -version
|
||||
kt:
|
||||
compile: echo "Invalid language selection"
|
||||
code_file: foo.kt
|
||||
@@ -119,6 +124,7 @@ langs:
|
||||
execute: /usr/bin/java -jar foo.jar
|
||||
display: Kotlin/JVM
|
||||
compile_time_limit: 30000
|
||||
version: /usr/bin/kotlinc -version
|
||||
py:
|
||||
compile: /usr/bin/python -c "import py_compile; py_compile.compile('/w/foo.py', '/w/foo', doraise=True)"
|
||||
code_file: foo.py
|
||||
@@ -132,38 +138,47 @@ langs:
|
||||
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
|
||||
version: /usr/bin/python3 --version
|
||||
py.pypy3:
|
||||
compile: /bin/bash -c "/usr/bin/pypy3 -c \"import py_compile; py_compile.compile('/w/foo.py', '/w/foo', doraise=True)\" && mv foo.py foo"
|
||||
execute: /bin/bash -c 'mv foo foo.py && /usr/bin/pypy3 -B foo.py'
|
||||
display: PyPy3
|
||||
version: /usr/bin/pypy3 --version
|
||||
php:
|
||||
execute: /usr/bin/php foo.php
|
||||
display: PHP
|
||||
version: /usr/bin/php -v
|
||||
rs:
|
||||
compile: /usr/bin/rustc -O -o /w/foo /w/foo.rs
|
||||
highlight: rust
|
||||
display: Rust
|
||||
version: /usr/bin/rustc --version
|
||||
hs:
|
||||
compile: /usr/bin/ghc -O -outputdir /tmp -o foo foo.hs
|
||||
highlight: haskell
|
||||
display: Haskell
|
||||
version: /usr/bin/ghc --version
|
||||
js:
|
||||
execute: /usr/bin/node /w/foo.js
|
||||
highlight: javascript
|
||||
display: NodeJS
|
||||
version: /usr/bin/node --version
|
||||
go:
|
||||
compile: /usr/bin/go build -o foo foo.go
|
||||
display: Golang
|
||||
version: /usr/bin/go version
|
||||
rb:
|
||||
execute: /usr/bin/ruby foo.rb
|
||||
highlight: ruby
|
||||
display: Ruby
|
||||
version: /usr/bin/ruby --version
|
||||
cs:
|
||||
compile: /usr/bin/mcs -optimize+ -out:/w/foo /w/foo.cs
|
||||
execute: /usr/bin/mono foo
|
||||
highlight: csharp
|
||||
monaco: csharp
|
||||
display: 'C#'
|
||||
version: /usr/bin/mcs --version
|
||||
r:
|
||||
display: R
|
||||
execute: /bin/sh -c "cat /dev/stdin >stdin && /usr/bin/Rscript --vanilla foo.r"
|
||||
|
||||
@@ -25,11 +25,41 @@ async function getStatus() {
|
||||
class StatusHandler extends Handler {
|
||||
async get() {
|
||||
const stats = await getStatus();
|
||||
const compilers = {};
|
||||
const warn = {};
|
||||
const result: Array<{ key: string[], message: string }> = [];
|
||||
// For each language, select the most common compiler message version,
|
||||
// then merge languages with the same message.
|
||||
for (const stat of stats) {
|
||||
if (!stat.battery.hasBattery) stat.battery = 'No battery';
|
||||
if (!stat.battery?.hasBattery) stat.battery = 'No battery';
|
||||
else stat.battery = `${stat.battery.type} ${stat.battery.model} ${stat.battery.percent}%${stat.battery.isCharging ? ' Charging' : ''}`;
|
||||
if (stat.compilers) {
|
||||
for (const key in stat.compilers) {
|
||||
if (!compilers[key]) compilers[key] ||= [];
|
||||
const related = compilers[key].find((i) => i.message === stat.compilers[key]);
|
||||
if (related) related.related.push(stat._id);
|
||||
else {
|
||||
compilers[key].push({
|
||||
related: [stat._id],
|
||||
message: stat.compilers[key],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.response.body = { stats };
|
||||
for (const key in compilers) {
|
||||
compilers[key].sort((a, b) => b.related.length - a.related.length);
|
||||
const message = compilers[key][0].message;
|
||||
for (let i = 1; i < compilers[key].length; i++) {
|
||||
for (const id of compilers[key][i].related) {
|
||||
warn[id] = true;
|
||||
}
|
||||
}
|
||||
const t = result.find((i) => i.message === message);
|
||||
if (t) t.key.push(key);
|
||||
else result.push({ key: [key], message });
|
||||
}
|
||||
this.response.body = { stats, compilers: result };
|
||||
this.response.template = 'status.html';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ export interface LangConfig {
|
||||
comment?: string | [string, string];
|
||||
compile_time_limit?: number;
|
||||
compile_memory_limit?: number;
|
||||
version?: string;
|
||||
}
|
||||
|
||||
export function parseLang(config: string): Record<string, LangConfig> {
|
||||
|
||||
Reference in new issue
Block a user