Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added image with c++ #9

Merged
merged 9 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,20 @@ jobs:
image_name_tag: hyperskill-go:1.18.2
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
build_hyperskill_gcc_image:
name: Build epicbox-hyperskill/gcc image
needs: build_debian_image
runs-on: [ self-hosted, small ]
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Build
uses: ./.github/workflows/actions/build
with:
path: epicbox-hyperskill/gcc
image_name_tag: hyperskill-gcc:10.2.1
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
build_hyperskill_gradle_image:
name: Build epicbox-hyperskill/gradle image
runs-on: [self-hosted, small]
Expand Down
31 changes: 31 additions & 0 deletions epicbox-hyperskill/gcc/Dockerfile
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
meanmail marked this conversation as resolved.
Show resolved Hide resolved

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/
3 changes: 3 additions & 0 deletions epicbox-hyperskill/gcc/checker/check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh
cd /sandbox
python3 /checker/process.py
14 changes: 14 additions & 0 deletions epicbox-hyperskill/gcc/checker/process.py
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))
97 changes: 97 additions & 0 deletions epicbox-hyperskill/gcc/checker/process_java.py
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()
52 changes: 52 additions & 0 deletions epicbox-hyperskill/gcc/checker/process_python.py
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, '')
74 changes: 74 additions & 0 deletions epicbox-hyperskill/gcc/checker/util.py
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)