apply languages
This commit is contained in:
15
CheckerExecutor/Dockerfile
Normal file
15
CheckerExecutor/Dockerfile
Normal file
@@ -0,0 +1,15 @@
|
||||
FROM docker:dind
|
||||
|
||||
RUN apk add --update --no-cache python3 && ln -sf python3 /usr/bin/python
|
||||
RUN python3 -m ensurepip
|
||||
RUN apk update && apk add postgresql-dev gcc python3-dev musl-dev jpeg-dev zlib-dev libjpeg
|
||||
RUN pip3 install --no-cache --upgrade pip setuptools
|
||||
RUN addgroup -S docker
|
||||
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
RUN mkdir -p /usr/src/app/
|
||||
WORKDIR /usr/src/app/
|
||||
|
||||
COPY . /usr/src/app/
|
||||
|
||||
CMD ["python", "main.py"]
|
0
CheckerExecutor/__init__.py
Normal file
0
CheckerExecutor/__init__.py
Normal file
64
CheckerExecutor/language.py
Normal file
64
CheckerExecutor/language.py
Normal file
@@ -0,0 +1,64 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class Language:
|
||||
id: int
|
||||
name: str
|
||||
work_name: str
|
||||
file_type: str
|
||||
logo_url: str
|
||||
image: str
|
||||
highlight: str
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
languages = [
|
||||
Language(
|
||||
id=0,
|
||||
name="Python3",
|
||||
work_name="Python3",
|
||||
file_type="py",
|
||||
logo_url="https://entredatos.es/wp-content/uploads/2021/05/1200px-Python-logo-notext.svg.png",
|
||||
image="python:3.6",
|
||||
highlight="python",
|
||||
),
|
||||
Language(
|
||||
id=1,
|
||||
name="Kotlin",
|
||||
work_name="Kotlin",
|
||||
file_type="kt",
|
||||
logo_url="https://upload.wikimedia.org/wikipedia/commons/0/06/Kotlin_Icon.svg",
|
||||
image="zenika/kotlin",
|
||||
highlight="kotlin",
|
||||
),
|
||||
Language(
|
||||
id=2,
|
||||
name="C++",
|
||||
work_name="Cpp",
|
||||
file_type="cpp",
|
||||
logo_url="https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/ISO_C%2B%2B_Logo.svg/1822px-ISO_C%2B%2B_Logo.svg.png",
|
||||
image="gcc",
|
||||
highlight="cpp",
|
||||
),
|
||||
Language(
|
||||
id=3,
|
||||
name="Java",
|
||||
work_name="Java",
|
||||
file_type="java",
|
||||
logo_url="https://upload.wikimedia.org/wikipedia/ru/thumb/3/39/Java_logo.svg/1200px-Java_logo.svg.png",
|
||||
image="openjdk",
|
||||
highlight="java",
|
||||
),
|
||||
Language(
|
||||
id=4,
|
||||
name="C#",
|
||||
work_name="CSharp",
|
||||
file_type="cs",
|
||||
logo_url="https://cdn.worldvectorlogo.com/logos/c--4.svg",
|
||||
image="mono",
|
||||
highlight="csharp",
|
||||
),
|
||||
]
|
67
CheckerExecutor/main.py
Normal file
67
CheckerExecutor/main.py
Normal file
@@ -0,0 +1,67 @@
|
||||
from multiprocessing import Process
|
||||
from os import getenv
|
||||
from os.path import join
|
||||
from tempfile import TemporaryDirectory
|
||||
from time import sleep
|
||||
from zipfile import ZipFile
|
||||
|
||||
from requests import get
|
||||
|
||||
from language import languages
|
||||
from testers import *
|
||||
|
||||
|
||||
def process_solution(path, data, language_id, solution_id, timeout):
|
||||
with open(join(path, "package.zip"), 'wb') as fs:
|
||||
fs.write(data)
|
||||
with ZipFile(join(path, "package.zip"), 'r') as zip_ref:
|
||||
zip_ref.extractall(path)
|
||||
language = languages[language_id]
|
||||
try:
|
||||
result = eval(language.work_name + "Tester")(path, solution_id, language_id, timeout).execute()
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
result = "TE"
|
||||
return result
|
||||
|
||||
|
||||
def poll(token):
|
||||
while True:
|
||||
print(get("http://127.0.0.1:8000/checker/status", params={"token": token}).json())
|
||||
sleep(2)
|
||||
|
||||
|
||||
def main():
|
||||
request = get("http://127.0.0.1:8000/checker/get_dynamic", params={"token": getenv("TOKEN")})
|
||||
if request.status_code != 200:
|
||||
print("Error happened: " + request.json()['status'])
|
||||
exit(1)
|
||||
dynamic_token = request.json()['token']
|
||||
p = Process(target=poll, args=(dynamic_token,))
|
||||
p.start()
|
||||
while True:
|
||||
data = get("http://127.0.0.1:8000/checker/available", params={"token": dynamic_token})
|
||||
if data.status_code == 200:
|
||||
sleep(2)
|
||||
continue
|
||||
elif data.status_code == 201:
|
||||
with TemporaryDirectory() as tempdir:
|
||||
result = process_solution(
|
||||
tempdir,
|
||||
data.content,
|
||||
int(data.headers['language_id']),
|
||||
int(data.headers['solution_id']),
|
||||
int(data.headers['timeout']),
|
||||
)
|
||||
get("http://127.0.0.1:8000/checker/set_result", params={
|
||||
"token": dynamic_token,
|
||||
"solution_id": data.headers['solution_id'],
|
||||
"result": result
|
||||
})
|
||||
|
||||
else:
|
||||
print("unknown status")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
115
CheckerExecutor/testers/BaseTester.py
Normal file
115
CheckerExecutor/testers/BaseTester.py
Normal file
@@ -0,0 +1,115 @@
|
||||
from os import listdir
|
||||
from os.path import join, exists
|
||||
from subprocess import call, TimeoutExpired
|
||||
|
||||
from language import *
|
||||
|
||||
|
||||
class TestException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class BaseTester:
|
||||
working_directory = "app"
|
||||
checker_code = None
|
||||
|
||||
def exec_command(self, command, working_directory="app", timeout=None):
|
||||
return call(
|
||||
f'docker exec -i solution sh -c "cd {working_directory} && {command}"',
|
||||
shell=True,
|
||||
timeout=timeout,
|
||||
)
|
||||
|
||||
def before_test(self):
|
||||
files = [
|
||||
file
|
||||
for file in listdir(self.path)
|
||||
if file.endswith("." + self.language.file_type)
|
||||
]
|
||||
code = self.exec_command(
|
||||
f'{self.build_command} {" ".join(files)}',
|
||||
working_directory=self.working_directory,
|
||||
)
|
||||
if code != 0:
|
||||
raise TestException("CE")
|
||||
|
||||
def test(self, filename):
|
||||
code = self.exec_command(
|
||||
f"< {filename} {self.command} > output.txt",
|
||||
timeout=self.timeout / 1000,
|
||||
)
|
||||
if code != 0:
|
||||
raise TestException("RE")
|
||||
result = open(join(self.path, "output.txt"), "r").read().strip().replace('\r\n', '\n')
|
||||
print("got result", result)
|
||||
if self.checker_code is not None:
|
||||
print('using checker')
|
||||
with open(join(self.path, 'expected.txt'), 'w') as fs:
|
||||
fs.write(self.predicted)
|
||||
with open(join(self.path, 'checker.py'), 'w') as fs:
|
||||
fs.write(self.checker_code)
|
||||
code = call(f'docker exec -i checker sh -c "cd app && python checker.py"', shell=True, timeout=1)
|
||||
if code != 0:
|
||||
raise TestException("WA")
|
||||
else:
|
||||
print('using simple check')
|
||||
if result != self.predicted:
|
||||
print('incorrect')
|
||||
raise TestException("WA")
|
||||
print('correct')
|
||||
|
||||
def after_test(self):
|
||||
pass
|
||||
|
||||
@property
|
||||
def command(self):
|
||||
return "./executable.exe"
|
||||
|
||||
@property
|
||||
def build_command(self):
|
||||
return ""
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
return self._path
|
||||
|
||||
@property
|
||||
def language(self):
|
||||
return languages[self.language_id]
|
||||
|
||||
def __init__(self, path, solution_id, language_id, timeout):
|
||||
self.solution_id = solution_id
|
||||
self._path = path
|
||||
self.language_id = language_id
|
||||
self.timeout = timeout
|
||||
|
||||
def execute(self):
|
||||
docker_command = f"docker run --name solution --volume={self.path}:/{self.working_directory} -t -d {self.language.image}"
|
||||
print(docker_command)
|
||||
call(docker_command, shell=True)
|
||||
checker = join(self.path, 'checker.py')
|
||||
if exists(checker):
|
||||
self.checker_code = open(checker, 'r').read()
|
||||
call(f"docker run --name checker --volume={self.path}:/app -t -d python:3.6", shell=True)
|
||||
print("Container created")
|
||||
result = None
|
||||
try:
|
||||
self.before_test()
|
||||
print("before test finished")
|
||||
for file in listdir(self.path):
|
||||
if not file.endswith(".a") and exists(join(self.path, file + '.a')):
|
||||
self.predicted = open(join(self.path, file + '.a'), 'r').read().strip().replace('\r\n', '\n')
|
||||
print('predicted:', self.predicted)
|
||||
self.test(file)
|
||||
self.after_test()
|
||||
result = "OK"
|
||||
except TestException as e:
|
||||
result = str(e)
|
||||
except TimeoutExpired:
|
||||
result = "TL"
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
result = "TE"
|
||||
call(f"docker rm --force solution", shell=True)
|
||||
call(f"docker rm --force checker", shell=True)
|
||||
return result
|
11
CheckerExecutor/testers/CSharpTester.py
Normal file
11
CheckerExecutor/testers/CSharpTester.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from .BaseTester import BaseTester
|
||||
|
||||
|
||||
class CSharpTester(BaseTester):
|
||||
@property
|
||||
def build_command(self):
|
||||
return "csc /out:executable.exe"
|
||||
|
||||
@property
|
||||
def command(self):
|
||||
return "mono executable.exe"
|
7
CheckerExecutor/testers/CppTester.py
Normal file
7
CheckerExecutor/testers/CppTester.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from .BaseTester import BaseTester
|
||||
|
||||
|
||||
class CppTester(BaseTester):
|
||||
@property
|
||||
def build_command(self):
|
||||
return "g++ -o executable.exe"
|
8
CheckerExecutor/testers/GoTester.py
Normal file
8
CheckerExecutor/testers/GoTester.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from .BaseTester import BaseTester
|
||||
|
||||
|
||||
class GoTester(BaseTester):
|
||||
working_directory = "../app"
|
||||
|
||||
def build_command(self):
|
||||
return "go build -o executable.exe"
|
27
CheckerExecutor/testers/JavaTester.py
Normal file
27
CheckerExecutor/testers/JavaTester.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from os import listdir
|
||||
|
||||
from .BaseTester import BaseTester, TestException
|
||||
|
||||
|
||||
class JavaTester(BaseTester):
|
||||
_executable = None
|
||||
|
||||
def before_test(self):
|
||||
files = [
|
||||
file
|
||||
for file in listdir(self.path)
|
||||
if file.endswith(".java")
|
||||
]
|
||||
code = self.exec_command(f"javac {' '.join(files)}")
|
||||
if code != 0:
|
||||
raise TestException("CE")
|
||||
for file in listdir(self.path):
|
||||
if file.endswith(".class"):
|
||||
self._executable = file.rstrip(".class")
|
||||
break
|
||||
if self._executable is None:
|
||||
raise TestException("TE")
|
||||
|
||||
@property
|
||||
def command(self):
|
||||
return f"java -classpath . {self._executable}"
|
21
CheckerExecutor/testers/KotlinTester.py
Normal file
21
CheckerExecutor/testers/KotlinTester.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from os import listdir
|
||||
|
||||
from .BaseTester import BaseTester, TestException
|
||||
|
||||
|
||||
class KotlinTester(BaseTester):
|
||||
def before_test(self):
|
||||
files = [
|
||||
file
|
||||
for file in listdir(self.path)
|
||||
if file.endswith(".kt")
|
||||
]
|
||||
code = self.exec_command(
|
||||
f'kotlinc {" ".join(files)} -include-runtime -d solution.jar'
|
||||
)
|
||||
if code != 0:
|
||||
raise TestException("CE")
|
||||
|
||||
@property
|
||||
def command(self):
|
||||
return "java -jar solution.jar"
|
19
CheckerExecutor/testers/Python3Tester.py
Normal file
19
CheckerExecutor/testers/Python3Tester.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from os import listdir
|
||||
|
||||
from .BaseTester import BaseTester, TestException
|
||||
|
||||
|
||||
class Python3Tester(BaseTester):
|
||||
file = None
|
||||
|
||||
def before_test(self):
|
||||
for file in listdir(self.path):
|
||||
if file.endswith(".py") and file != 'checker.py':
|
||||
self.file = file
|
||||
break
|
||||
if self.file is None:
|
||||
raise TestException("TE")
|
||||
|
||||
@property
|
||||
def command(self):
|
||||
return f"python3 {self.file}"
|
7
CheckerExecutor/testers/__init__.py
Normal file
7
CheckerExecutor/testers/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from .BaseTester import BaseTester
|
||||
from .Python3Tester import Python3Tester
|
||||
from .CppTester import CppTester
|
||||
from .GoTester import GoTester
|
||||
from .JavaTester import JavaTester
|
||||
from .CSharpTester import CSharpTester
|
||||
from .KotlinTester import KotlinTester
|
Reference in New Issue
Block a user