apply languages

This commit is contained in:
Egor Matveev
2022-02-16 17:40:46 +03:00
parent 1e455346ff
commit 2948c8252e
39 changed files with 758 additions and 12 deletions

View 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"]

View File

View 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
View 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()

View 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

View 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"

View File

@@ -0,0 +1,7 @@
from .BaseTester import BaseTester
class CppTester(BaseTester):
@property
def build_command(self):
return "g++ -o executable.exe"

View 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"

View 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}"

View 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"

View 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}"

View 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