Skip to content
This repository has been archived by the owner on Jul 22, 2022. It is now read-only.

Commit

Permalink
Merge pull request #6 from wangxinhe2006/dev
Browse files Browse the repository at this point in the history
Bump version number to v0.5
  • Loading branch information
wxh06 authored Nov 23, 2019
2 parents 77c55f2 + a326949 commit 9eb8c9d
Show file tree
Hide file tree
Showing 8 changed files with 323 additions and 186 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/pythonpublish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Upload Python Package

on:
release:
types: [created]

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ before_install:
- pip install -U setuptools
install:
- pip install -r requirements.txt
- pip install pycodestyle pylint
- pip install flake8
script:
- pycodestyle setup.py dockerjudge
- pylint dockerjudge
- flake8 dockerjudge
- python3 -W ignore tests.py
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"python.linting.pycodestyleEnabled": true,
"python.linting.flake8Enabled": true,
"python.pythonPath": "venv/bin/python"
}
195 changes: 109 additions & 86 deletions dockerjudge/__init__.py
Original file line number Diff line number Diff line change
@@ -1,86 +1,109 @@
'dockerjudge - A Docker Based Online Judge Engine'

from pprint import pprint
import re
import shlex
import sys
import threading

import docker
import ruamel.yaml

__version__ = '0.4'


class Thread(threading.Thread):
'Subclass of threading.Thread with return value'
return_value = 'UE' # Unknown Error

def run(self):
try:
if self._target:
self.return_value = self._target(*self._args, **self._kwargs)
finally:
del self._target, self._args, self._kwargs


def _judge(container, commands, stdio, timeout=1):
'Run each test case'
if commands[0]:
container.exec_run(commands[0])
result = container.exec_run(['bash', '-c', 'time echo {}|timeout -s KILL '
'{} {}'.format(shlex.quote(stdio[0]), timeout,
commands[1])], demux=True)
duration = re.search('real\t([0-9]+)m([0-9]+\\.[0-9]{3})s\n'
'user\t[0-9]+m[0-9]+\\.[0-9]{3}s\n'
'sys\t[0-9]+m[0-9]+\\.[0-9]{3}s\n$',
result.output[1].decode())
duration = int(duration.group(1)) * 60 + float(duration.group(2))
if commands[2]:
container.exec_run(commands[2])
if result.exit_code == 137:
return ('TLE', duration) # Time Limit Exceeded
if result.exit_code:
return ('RE', duration) # Runtime Error
if (result.output[0] or b'').decode().rstrip() != stdio[1].rstrip():
return ('WA', duration) # Wrong Answer
return ('AC', duration) # Accepted


def judge(settings, source='', tests=(), timeout=1, client=docker.from_env()):
'Main judge function'
container = client.containers.run(settings['image'], detach=True,
network_disabled=True, tty=True)
try:
container.exec_run(['bash', '-c', 'echo {} > {}'.format(
shlex.quote(source), settings['source'])])
if 'before_compile' in settings:
container.exec_run(settings['before_compile'])
compiler = container.exec_run(settings['compile'], demux=True)
if 'before_compile' in settings:
container.exec_run(settings['after_compile'])
if compiler.exit_code:
result = [('CE', .0) for test in tests]
else:
threads = []
for stdin, stdout in tests:
thread = Thread(target=_judge,
args=(container, (settings.get('before_judge'),
settings['judge'],
settings.get('after_judge')),
(stdin, stdout), timeout))
thread.start()
threads.append(thread)
result = []
for thread in threads:
thread.join()
result.append(thread.return_value)
return [result, (compiler.output[1] or b'').decode()]
finally:
container.remove(force=True)


if __name__ == '__main__':
pprint(judge(ruamel.yaml.YAML().load(open('settings.yaml'))
[sys.argv[1]][sys.argv[2]],
sys.stdin.read(), zip(sys.argv[3::2], sys.argv[4::2])))
'dockerjudge - A Docker Based Online Judge Engine'

from pprint import pprint
import re
import shlex
import sys
import threading

import docker
import ruamel.yaml

__version__ = '0.5'


class Thread(threading.Thread):
'Subclass of threading.Thread with return value'
return_value = 'UE' # Unknown Error

def run(self):
try:
if self._target:
self.return_value = self._target(*self._args, **self._kwargs)
finally:
del self._target, self._args, self._kwargs


def _judge(dir, container, commands, stdio, timeout, iofn):
'Run each test case'
if commands[0]:
container.exec_run(commands[0])
container.exec_run(['bash', '-c', 'mkdir {}'.format(dir)])
if iofn[0]:
container.exec_run(['bash', '-c', 'echo {}>'
'{}/{}'.format(shlex.quote(stdio[0]),
dir, iofn[0])])
result = container.exec_run(['bash', '-c', 'cd {}&&time timeout -s '
'KILL {} {}<{}'.format(dir, timeout,
commands[1] % '..',
iofn[0])],
demux=True)
else:
result = container.exec_run(['bash', '-c', 'cd {}&&time echo {}|'
'timeout -s KILL {} '
'{}'.format(dir, shlex.quote(stdio[0]),
timeout, commands[1] % '..')],
demux=True)
if iofn[1]:
cat = container.exec_run(['bash', '-c',
'cat {}/{}'.format(dir, iofn[1])],
demux=True)
output = cat.output[0]
else:
output = result.output[0]
duration = re.search('real\t([0-9]+)m([0-9]+\\.[0-9]{3})s\n'
'user\t[0-9]+m[0-9]+\\.[0-9]{3}s\n'
'sys\t[0-9]+m[0-9]+\\.[0-9]{3}s\n$',
result.output[1].decode())
duration = int(duration.group(1)) * 60 + float(duration.group(2))
if commands[2]:
container.exec_run(commands[2])
if result.exit_code == 137:
return ('TLE', duration) # Time Limit Exceeded
if result.exit_code:
return ('RE', duration) # Runtime Error
if (output or b'').decode().rstrip() != stdio[1].rstrip():
return ('WA', duration) # Wrong Answer
return ('AC', duration) # Accepted


def judge(settings, source='', tests=[], timeout=1, iofn=(None, None),
client=docker.from_env()):
'Main judge function'
tests = list(tests)
container = client.containers.run(settings['image'], detach=True,
network_disabled=True, tty=True)
try:
container.exec_run(['bash', '-c', 'echo {} > {}'.format(
shlex.quote(source), settings['source'])])
if 'before_compile' in settings:
container.exec_run(settings['before_compile'])
compiler = container.exec_run(settings['compile'], demux=True)
if 'before_compile' in settings:
container.exec_run(settings['after_compile'])
if compiler.exit_code:
result = [('CE', .0) for test in tests]
else:
threads = []
for i in range(len(tests)):
thread = Thread(target=_judge,
args=(i, container,
(settings.get('before_judge'),
settings['judge'],
settings.get('after_judge')),
tests[i], timeout, iofn))
thread.start()
threads.append(thread)
result = []
for thread in threads:
thread.join()
result.append(thread.return_value)
return [result, (compiler.output[1] or b'').decode()]
finally:
container.remove(force=True)


if __name__ == '__main__':
pprint(judge(ruamel.yaml.YAML().load(open('settings.yaml'))
[sys.argv[1]][sys.argv[2]],
sys.stdin.read(), zip(sys.argv[3::2], sys.argv[4::2])))
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
docker[tls]>=3.7
ruamel.yaml
docker[tls]>=3.7
ruamel.yaml
Loading

0 comments on commit 9eb8c9d

Please sign in to comment.