forked from StepicOrg/epicbox-images
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* added image with c++ * Update epicbox-hyperskill/cpp/Dockerfile Co-authored-by: Alexander Petrov <[email protected]> * Update epicbox-hyperskill/cpp/Dockerfile Co-authored-by: Alexander Petrov <[email protected]> * reformat image for hyperskill/c++ * Update epicbox-hyperskill/gcc/Dockerfile Co-authored-by: Alexander Petrov <[email protected]> * reformat image for hyperskill/c++ * updated ci.yml * updated ci.yml, reformat Dockerfile * reformat hyperskill-gcc --------- Co-authored-by: Alexander Petrov <[email protected]>
- Loading branch information
1 parent
7b336ae
commit 9211a2f
Showing
7 changed files
with
285 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
FROM hyperskill.azurecr.io/epicbox/debian:bullseye | ||
|
||
ENV GCC_VERSION 10.2.1-1 | ||
|
||
RUN apt-get update \ | ||
&& apt-get install -y --no-install-recommends \ | ||
bash \ | ||
cmake \ | ||
curl \ | ||
gcc=4:${GCC_VERSION} \ | ||
gcc-multilib=4:${GCC_VERSION} \ | ||
g++=4:${GCC_VERSION} \ | ||
make \ | ||
python3 \ | ||
python3-dev \ | ||
python3-pip \ | ||
unzip \ | ||
&& rm -rf /var/lib/apt/lists/* \ | ||
&& pip3 install https://github.com/hyperskill/hs-test-python/archive/refs/tags/v11.0.0.tar.gz \ | ||
&& mkdir /checker \ | ||
&& curl -L -o /checker/kotlin.zip \ | ||
https://github.com/JetBrains/kotlin/releases/download/v1.9.10/kotlin-compiler-1.9.10.zip \ | ||
&& unzip /checker/kotlin.zip -d /checker \ | ||
&& apt-get remove -y unzip \ | ||
&& rm /checker/kotlin.zip \ | ||
&& curl -L -o /checker/hs-test.jar \ | ||
https://github.com/hyperskill/hs-test/releases/download/v11.0.0/hs-test-v11.0.0.jar | ||
|
||
ENV PATH="/checker/kotlinc/bin:$PATH" | ||
|
||
COPY checker /checker/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#!/bin/sh | ||
cd /sandbox | ||
python3 /checker/process.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from process_java import is_java_tests, process_java | ||
from process_python import is_python_tests, process_python | ||
from util import finish_badly, format_exception | ||
|
||
if __name__ == '__main__': | ||
try: | ||
if is_python_tests(): | ||
process_python() | ||
elif is_java_tests(): | ||
process_java() | ||
else: | ||
finish_badly("Cannot find tests for the task") | ||
except Exception as ex: | ||
finish_badly(format_exception(ex)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import os | ||
|
||
from util import finish, finish_badly, run_process, TASK_ROOT | ||
|
||
HSTEST_JAR = f'/checker/hs-test.jar' | ||
KOTLIN_JAR = f'/checker/kotlinc/lib/kotlin-stdlib.jar' | ||
|
||
CLASSES_FOLDER = f'{TASK_ROOT}/out' | ||
MODULES = [ | ||
f'{TASK_ROOT}/src', | ||
f'{TASK_ROOT}/test', | ||
f'{TASK_ROOT}/util/src', | ||
f'{TASK_ROOT}/util/test', | ||
] | ||
|
||
COMPILE_OPTIONS = [ | ||
'-cp', HSTEST_JAR, '-d', CLASSES_FOLDER | ||
] | ||
|
||
JAVA_EXECUTE = [ | ||
'java', '-cp', f'{HSTEST_JAR}:{KOTLIN_JAR}:{CLASSES_FOLDER}', '-ea', | ||
f'-DinsideDocker=true', | ||
f'-DignoreStdout=true', | ||
f'-Duser.dir={TASK_ROOT}', | ||
f'-Dfile.encoding=utf-8', | ||
'org.hyperskill.hstest.stage.StageTest' | ||
] | ||
|
||
|
||
def is_java_tests() -> bool: | ||
tests_folder = f'{TASK_ROOT}/test' | ||
|
||
if not os.path.isdir(tests_folder): | ||
return False | ||
|
||
for path, folders, files in os.walk(tests_folder): | ||
for file in files: | ||
if file.endswith('.java') or file.endswith('.kt'): | ||
return True | ||
|
||
return False | ||
|
||
|
||
def compilation_error_feedback(stderr: str) -> str: | ||
lines = stderr.strip().splitlines() | ||
output = [] | ||
|
||
for line in lines: | ||
if line.startswith(TASK_ROOT): | ||
line = line.replace(TASK_ROOT, '', 1) | ||
output.append(line) | ||
|
||
return 'Compilation error\n\n' + '\n'.join(output).strip() | ||
|
||
|
||
def compile_files(compiler: str, extension: str): | ||
compile_command = [compiler] + COMPILE_OPTIONS | ||
|
||
files_to_compile = [] | ||
|
||
for module in MODULES: | ||
for path, folders, files in os.walk(module): | ||
for file in files: | ||
if file.endswith(extension): | ||
files_to_compile += [os.path.join(path, file)] | ||
|
||
if not files_to_compile: | ||
return | ||
|
||
code, out, err = run_process(compile_command + files_to_compile) | ||
|
||
if code != 0: | ||
finish(False, compilation_error_feedback(out + '\n' + err)) | ||
|
||
|
||
def run_java(): | ||
code, out, err = run_process(JAVA_EXECUTE) | ||
out = out.strip() | ||
err = err.strip() | ||
|
||
if code != 0: | ||
if len(out) == 0 and len(err) == 0: | ||
finish_badly(f'No stdout, no stderr, code = {code}') | ||
|
||
if len(out): | ||
finish(False, out) | ||
|
||
if len(err): | ||
finish(False, err) | ||
|
||
finish(True, '') | ||
|
||
|
||
def process_java(): | ||
compile_files('javac', '.java') | ||
compile_files('kotlinc', '.kt') | ||
run_java() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import os.path | ||
|
||
from util import TASK_ROOT, finish, finish_badly, run_process | ||
|
||
FAILED_TEST_BEGIN = '#educational_plugin FAILED + ' | ||
FAILED_TEST_CONTINUE = '#educational_plugin ' | ||
|
||
TESTS_FILES = [ | ||
f'{TASK_ROOT}/tests.py', | ||
f'{TASK_ROOT}/test/tests.py' | ||
] | ||
|
||
|
||
def is_python_tests() -> bool: | ||
return any(os.path.isfile(f) for f in TESTS_FILES) | ||
|
||
|
||
def process_python(): | ||
test_file = '' | ||
for file in TESTS_FILES: | ||
if os.path.isfile(file): | ||
test_file = file | ||
break | ||
|
||
python_execute_command = [ | ||
'python3', test_file, '--inside_docker' | ||
] | ||
|
||
code, out, err = run_process(python_execute_command) | ||
out = out.strip().splitlines() | ||
|
||
if code != 0: | ||
finish_badly(f'Exit code = {code}') | ||
|
||
if any(line.startswith(FAILED_TEST_BEGIN) for line in out): | ||
output = [] | ||
output_started = False | ||
|
||
for line in out: | ||
if output_started and line.startswith(FAILED_TEST_CONTINUE): | ||
output.append(line[len(FAILED_TEST_CONTINUE):]) | ||
|
||
if not output_started and line.startswith(FAILED_TEST_BEGIN): | ||
output_started = True | ||
output.append(line[len(FAILED_TEST_BEGIN):]) | ||
|
||
feedback = '\n'.join(output).strip() | ||
|
||
finish(False, feedback) | ||
|
||
else: | ||
finish(True, '') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import json | ||
import subprocess | ||
import sys | ||
import traceback | ||
|
||
TASK_ROOT = '/sandbox' | ||
|
||
all_stdout = [] | ||
all_stderr = [] | ||
|
||
|
||
def finish(successful: bool, feedback: str): | ||
score = 1 if successful else 0 | ||
|
||
if '--debug' in sys.argv: | ||
print(f'Score: {score}\nFeedback:\n{feedback}') | ||
|
||
else: | ||
result = { | ||
'score': score, | ||
'feedback': feedback, | ||
} | ||
print(json.dumps(result, sort_keys=True)) | ||
|
||
exit(0) | ||
|
||
|
||
def finish_badly(reason: str = ''): | ||
bad_feedback = ( | ||
'Cannot check the submission.\n' | ||
'\n' | ||
'Perhaps your program has fallen into an infinite loop or created too many objects in memory.\n' | ||
'If you are sure that this is not the case, please send the report to [email protected]\n' | ||
'\n' | ||
'reason:\n' | ||
'{reason}\n' | ||
'\n' | ||
'stdout:\n' | ||
'{stdout}\n' | ||
'\n' | ||
'stderr:\n' | ||
'{stderr}' | ||
.format(reason=reason, | ||
stdout='\n---\n'.join(all_stdout), | ||
stderr='\n---\n'.join(all_stderr)) | ||
) | ||
finish(False, bad_feedback) | ||
|
||
|
||
def run_process(args): | ||
proc = subprocess.Popen( | ||
args, | ||
stdout=subprocess.PIPE, | ||
stderr=subprocess.PIPE | ||
) | ||
exit_code = proc.wait() | ||
|
||
stdout = proc.stdout.read().decode().strip() | ||
stderr = proc.stderr.read().decode().strip() | ||
|
||
all_stdout.append(stdout) | ||
all_stderr.append(stderr) | ||
|
||
return exit_code, stdout, stderr | ||
|
||
|
||
def format_exception(ex): | ||
if sys.version_info >= (3, 10): | ||
traceback_stack = traceback.format_exception(ex) | ||
else: | ||
exc_tb = ex.__traceback__ | ||
traceback_stack = traceback.format_exception(etype=type(ex), value=ex, tb=exc_tb) | ||
|
||
return ''.join(traceback_stack) |