"""Processors
+---------------------------------------+--------------+-----------------+
| Processor | Language(s) |Required `Docker |
| | [*]_ |image <https:// |
| | |hub.docker.com>`_|
+=======================================+==============+=================+
| :class:`~dockerjudge.processor.Bash` | Shell | |bash|_ |
+---------------------------------------+--------------+-----------------+
| :class:`~dockerjudge.processor.Clang` | - C (``c``) | |clang|_ |
| | - **C++** | |
| | (``cpp``) | |
+---------------------------------------+--------------+-----------------+
| :class:`~dockerjudge.processor.GCC` | - C | |gcc|_ |
| | (``c``) | |
| | - **C++** | |
| | (``cpp``) | |
| | - Go | |
| | (``go``) | |
+---------------------------------------+--------------+-----------------+
| :class:`~dockerjudge.processor.Go` | Go | |golang|_ |
+---------------------------------------+--------------+-----------------+
| :class:`~dockerjudge.processor.Mono` |- Visual Basic| |mono|_ |
| | (``vb``) | |
| |- **C#** | |
| | (``csharp``)| |
+---------------------------------------+--------------+-----------------+
| :class:`~dockerjudge.processor.Node` | Node.js | |node|_ |
+---------------------------------------+--------------+-----------------+
|:class:`~dockerjudge.processor.OpenJDK`| Java | |openjdk|_ |
+---------------------------------------+--------------+-----------------+
| :class:`~dockerjudge.processor.PHP` | PHP | |php|_ |
+---------------------------------------+--------------+-----------------+
| :class:`~dockerjudge.processor.PyPy` | Python | |pypy|_ |
+---------------------------------------+--------------+-----------------+
| :class:`~dockerjudge.processor.Python`| Python | |python|_ |
+---------------------------------------+--------------+-----------------+
| :class:`~dockerjudge.processor.Ruby` | Ruby | |ruby|_ |
+---------------------------------------+--------------+-----------------+
| :class:`~dockerjudge.processor.Swift` | Swift | |swift|_ |
+---------------------------------------+--------------+-----------------+
.. https://docutils.sourceforge.io/FAQ.html#is-nested-inline-markup-possible
.. |node| replace:: `node`
.. _node: https://hub.docker.com/_/node
.. |openjdk| replace:: `openjdk`
.. _openjdk: https://hub.docker.com/_/openjdk
.. |php| replace:: `php`
.. _php: https://hub.docker.com/_/php
.. |pypy| replace:: `pypy`
.. _pypy: https://hub.docker.com/_/pypy
.. |python| replace:: `python`
.. _python: https://hub.docker.com/_/python
.. |ruby| replace:: `ruby`
.. _ruby: https://hub.docker.com/_/ruby
.. |swift| replace:: `swift`
.. _swift: https://hub.docker.com/_/swift
.. [*] Emboldened language by default.
"""
# pylint: disable = missing-function-docstring, too-few-public-methods
import shlex
from enum import Enum
from pathlib import PurePosixPath
[docs]class Processor:
"""Defines the operations of a multi-version programming language processor
================== ========================================
Data Type
================== ========================================
``image`` `str`
``workdir`` :class:`~pathlib.PurePosixPath` or `str`
``source`` `str`
``before_compile`` `str` or `list`
``compile`` `str` or `list`
``after_compile`` `str` or `list`
``before_judge`` `str` or `list`
``judge`` `str`
``after_judge`` `str` or `list`
================== ========================================
"""
@staticmethod
def _get_image_with_tag(image, tag):
return image + (f":{tag}" if tag else "")
image = None
workdir = PurePosixPath("/dockerjudge")
source = None
before_compile = None
compile = None
after_compile = None
before_judge = None
judge = None
after_judge = None
class _Language(Enum):
"Get programming language from enum"
@classmethod
def __get_language(cls, language, default=None):
if isinstance(language, cls):
return language
try:
return cls[language]
except KeyError:
try:
return cls(language)
except ValueError:
return cls.__get_language(default)
[docs]class Bash(Processor):
"""Bash is the GNU Project's Bourne Again SHell
:param version: Tag name of Docker image |bash|_
:type version: `str`, `int` or `float`
.. |bash| replace:: `bash`
.. _bash: https://hub.docker.com/_/bash
"""
def __init__(self, version=None):
self.image = self._get_image_with_tag("bash", version)
self.source = "bash.sh"
self.compile = ["bash", "-n", self.source]
self.judge = f"bash {self.source}"
[docs]class Clang(Processor):
"""Clang C Language Family Frontend for LLVM
:param language: Programming panguage
(``C``\\ /\\ `c` or ``C++``\\ /\\ ``cpp``), `C++` by default
:type language: :class:`dockerjudge.processor.Clang.Language` or `str`
:param version: Tag name of Docker image |clang|_
:type version: `str`, `int` or `float`
:param filenames: Filenames of source code and binary file,
C++ default: ``{'src': 'a.cpp', 'bin': None}``
:type filenames: `dict`
:param options: Compiler options
:type options: `list` or `str`
.. |clang| replace:: `clangbuiltlinux/ubuntu`
.. _clang: https://hub.docker.com/r/clangbuiltlinux/ubuntu
"""
class Language(_Language):
"""Programming language, `C` (``c``) or `C++` (``cpp``)
:C: ``Clang.Language.c``,
``Clang.Language['c']`` or ``Clang.Language('C')``
:C++: ``Clang.Language.cpp``,
``Clang.Language['cpp']`` or ``Clang.Language('C++')``
"""
c = "C"
cpp = "C++"
@classmethod
def _get_language(cls, language):
return super().__get_language(language, cls.cpp)
def __init__(
self, language=None, version=None, filenames=None, options=None
):
lang = self.Language._get_language(language)
fns = filenames or {}
args = options or []
self.image = "clangbuiltlinux/ubuntu" + f":llvm{version}-latest"
self.source = fns.get("src", f"a.{lang.name}")
self.compile = (
[
{self.Language.c: "clang", self.Language.cpp: "clang++"}[lang]
+ f"-{version}",
self.source,
]
+ (["-o", fns["bin"]] if fns.get("bin") else [])
+ (shlex.split(args) if isinstance(args, str) else args)
)
self.after_compile = ["rm", self.source]
self.judge = f"./{fns.get('bin', 'a.out')}"
[docs]class GCC(Processor):
"""GNU project C, C++ and Go compiler
:param language: Programming panguage
(``C``\\ /\\ ``c``, ``C++``\\ /\\ ``cpp`` or ``Go``\\ /\\ ``go``),
`C++` by default
:type language: :class:`dockerjudge.processor.GCC.Language` or `str`
:param version: Tag name of Docker image |gcc|_
:type version: `str`, `int` or `float`
:param filenames: Filenames of source code and binary file,
C++ default: ``{'src': 'a.cpp', 'bin': None}``
:type filenames: `dict`
:param options: Compiler options
:type options: `list` or `str`
.. |gcc| replace:: `gcc`
.. _gcc: https://hub.docker.com/_/gcc
"""
class Language(_Language):
"""Programming language, `C` (``c``), `C++` (``cpp``) or `Go` (``go``)
:C: ``GCC.Language.c``,
``GCC.Language['c']`` or ``GCC.Language('C')``
:C++: ``GCC.Language.cpp``,
``GCC.Language['cpp']`` or ``GCC.Language('C++')``
:Go: ``GCC.Language.go``,
``GCC.Language['go']`` or ``GCC.Language('Go')``
"""
c = "C"
cpp = "C++"
go = "Go"
@classmethod
def _get_language(cls, language):
return super().__get_language(language, cls.cpp)
def __init__(
self, language=None, version=None, filenames=None, options=None
):
lang = self.Language._get_language(language)
fns = filenames or {}
args = options or []
self.image = self._get_image_with_tag("gcc", version)
self.source = fns.get("src", f"a.{lang.name}")
self.compile = (
[
{
self.Language.c: "gcc",
self.Language.cpp: "g++",
self.Language.go: "gccgo",
}[lang],
self.source,
]
+ (["-o", fns["bin"]] if fns.get("bin") else [])
+ (shlex.split(args) if isinstance(args, str) else args)
)
self.after_compile = ["rm", self.source]
self.judge = f"./{fns.get('bin', 'a.out')}"
[docs]class Go(Processor):
"""The Go Programming Language
:param version: Tag name of Docker image |golang|_
:type version: `str`, `int` or `float`
:param filenames: Filenames of source code and binary file,
default: ``{'src': 'main.go', 'bin': None}``
:type filenames: `dict`
.. |golang| replace:: `golang`
.. _golang: https://hub.docker.com/_/golang
"""
def __init__(self, version=None, filenames=None, options=None):
fns = filenames or {}
args = options or []
self.image = self._get_image_with_tag("golang", version)
self.source = fns.get("src", "main.go")
self.compile = (
["go", "build"]
+ (["-o", fns["bin"]] if fns.get("bin") else [])
+ args
+ [self.source]
)
self.after_compile = ["rm", self.source]
self.judge = f"./{fns.get('bin', 'main')}"
[docs]class Mono(Processor):
"""**Mono** is a software platform
designed to allow developers to easily create
cross platform applications part of the `.NET Foundation`_.
Sponsored by Microsoft_,
Mono is an open source implementation of Microsoft's .NET Framework
based on the ECMA_ standards
for `C#`_ and the `Common Language Runtime`_.
:param language: Programming panguage
(``Visual Basic``\\ /\\ ``vb`` or ``C#``\\ /\\ ``csharp``),
C# by default
:type language: :class:`dockerjudge.processor.Mono.Language` or `str`
:param version: Tag name of Docker image |mono|_
:type version: `str`, `int` or `float`
.. _.NET Foundation: https://www.dotnetfoundation.org
.. _Microsoft: https://www.microsoft.com
.. _ECMA: https://www.mono-project.com/docs/about-mono/languages/ecma/
.. _C#: https://www.mono-project.com/docs/about-mono/languages/csharp/
.. _Common Language Runtime:
https://www.mono-project.com/docs/advanced/runtime/
.. |mono| replace:: `mono`
.. _mono: https://hub.docker.com/_/mono
"""
class Language(_Language):
"""Programming language, `Visual Basic` (``vb``) or `C#` (``csharp``)
:Visual Basic: ``GCC.Language.vb``,
``GCC.Language['vb']`` or ``GCC.Language('Visual Basic')``
:C#: ``GCC.Language.csharp``,
``GCC.Language['csharp']`` or ``GCC.Language('C#')``
"""
vb = "Visual Basic"
csharp = "C#"
@classmethod
def _get_language(cls, language):
return super().__get_language(language, cls.csharp)
def __init__(self, language=None, version=None):
lang = self.Language._get_language(language)
self.image = self._get_image_with_tag("mono", version)
self.source = f"""mono.{
{self.Language.csharp: 'cs', self.Language.vb: 'vb'}[lang]
}"""
self.compile = [
{self.Language.csharp: "csc", self.Language.vb: "vbnc"}[lang],
self.source,
]
self.after_compile = ["rm", self.source]
self.judge = "mono mono.exe"
[docs]class Node(Processor):
"Node.js®"
def __init__(self, version=None):
self.image = self._get_image_with_tag("node", version)
self.source = "index.js"
self.compile = ["node", "-c", self.source]
self.judge = f"node {self.source}"
[docs]class OpenJDK(Processor):
"Open Java Development Kit"
def __init__(self, version=None):
self.image = self._get_image_with_tag("openjdk", version)
self.source = "Main.java"
self.compile = ["javac", self.source]
self.after_compile = ["rm", self.source]
self.judge = "java Main"
[docs]class PHP(Processor):
"PHP"
def __init__(self, version=None):
self.image = self._get_image_with_tag("php", version)
self.source = "index.php"
self.compile = ["php", "-l", self.source]
self.judge = f"php {self.source}"
[docs]class PyPy(Processor):
"PyPy"
def __init__(self, version=None):
pypy = "pypy" if str(version).startswith("2") else "pypy3"
self.image = self._get_image_with_tag("pypy", version)
self.source = "__init__.py"
self.compile = [pypy, "-m", "compileall", "."]
self.judge = f"{pypy} {self.source}"
[docs]class Python(Processor):
"CPython"
def __init__(self, version=None):
self.image = self._get_image_with_tag("python", version)
self.source = "__init__.py"
self.compile = ["python", "-m", "compileall", "."]
self.judge = f"python {self.source}"
[docs]class Ruby(Processor):
"Ruby"
def __init__(self, version=None):
self.image = self._get_image_with_tag("ruby", version)
self.source = "ruby.rb"
self.compile = ["ruby", "-wc", self.source]
self.judge = f"ruby {self.source}"
[docs]class Swift(Processor):
"Swift"
def __init__(self, version=None):
self.image = self._get_image_with_tag("swift", version)
self.source = "main.swift"
self.compile = ["swiftc", self.source]
self.judge = "./main"