Skip to content
Open
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
18 changes: 0 additions & 18 deletions Dockerfile

This file was deleted.

4 changes: 3 additions & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ tox = "*"
[packages]
quart = "*"
quart-cors = "*"
aiodocker = "*"
python-dotenv = "*"
docker = "*"
inquirer = "*"
halo = "*"

[requires]
python_version = "3.7"
238 changes: 136 additions & 102 deletions Pipfile.lock

Large diffs are not rendered by default.

71 changes: 71 additions & 0 deletions cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import os

import inquirer
from inquirer.themes import GreenPassion

from src.utils.image_builder import Colorize, ImageBuilder


def get_languages() -> list:
"""Return a list a list of buildable languages
Assumes the following directory structure
docker/
lang1/
Dockerfile
lang2/
Dockerfile
lang3/
Dockerfile
"""
x = next(os.walk("docker/"))[1] # get only directories
x.remove("script") # remove script directory
return x


def ignore(answer: dict) -> bool:
if "all" in answer.get("action"):
return True
return False


def main(questions: list, languages: list):
option = inquirer.prompt(questions, theme=GreenPassion())
build_type = option.get("action") # Build type: all or selected
build_option = "rebuild" in build_type # build or rebuild
ib = ImageBuilder()
if "all" in build_type:
ib.create_images(languages, build_option)
else:
ib.create_images(option.get("partial_build"), build_option)


if __name__ == "__main__":
txt = (
"This script can build or rebuild the docker images specified in the docker folder."
"It will also generate the language_list file in src/ folder."
)
summary = Colorize.colorize(text=txt, colour="purple",)
print(summary)
languages = get_languages()
questions = [
inquirer.List(
name="action",
message="Select the appropriate action",
choices=[
"build all images",
"build selected images",
"rebuild all images",
"rebuild selected images",
],
),
inquirer.Checkbox(
name="partial_build",
message=(
"Select the language you want to install:"
"(press <space> to select, <enter> to finalize)"
),
choices=languages,
ignore=ignore,
),
]
main(questions, languages)
2 changes: 2 additions & 0 deletions .dockerignore → docker/.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
.gitignore
.github


.venv
temp/
demo/
5 changes: 5 additions & 0 deletions docker/gcc/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM mridul303/gcc-alpine:10.2.0
RUN mkdir /script && \
apk update \
rm -rf /var/cache/apk/*
COPY ./script /scripe
79 changes: 79 additions & 0 deletions docker/gcc/buld_from_source/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
FROM alpine as alpine

ARG GCC_VERSION
ENV GCC_VERSION=${GCC_VERSION}


FROM alpine as builder

RUN apk add --quiet --no-cache \
build-base \
dejagnu \
isl-dev \
make \
mpc1-dev \
mpfr-dev \
texinfo \
zlib-dev
RUN wget -q https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VERSION}/gcc-${GCC_VERSION}.tar.gz && \
tar -xzf gcc-${GCC_VERSION}.tar.gz && \
rm -f gcc-${GCC_VERSION}.tar.gz

WORKDIR /gcc-${GCC_VERSION}

RUN ./configure \
--prefix=/usr/local \
--build=$(uname -m)-alpine-linux-musl \
--host=$(uname -m)-alpine-linux-musl \
--target=$(uname -m)-alpine-linux-musl \
--with-pkgversion="Alpine ${GCC_VERSION}" \
--enable-checking=release \
--disable-fixed-point \
--disable-libmpx \
--disable-libmudflap \
--disable-libsanitizer \
--disable-libssp \
--disable-libstdcxx-pch \
--disable-multilib \
--disable-nls \
--disable-symvers \
--disable-werror \
--enable-__cxa_atexit \
--enable-default-pie \
--enable-languages=c,c++ \
--enable-shared \
--enable-threads \
--enable-tls \
--with-linker-hash-style=gnu \
--with-system-zlib
RUN make --silent -j $(nproc)
RUN make --silent -j $(nproc) install-strip

RUN ln -s /usr/bin/gcc /usr/local/bin/cc

RUN gcc -v


FROM alpine:3.12

RUN apk update; \
apk add --quiet --no-cache \
autoconf \
automake \
binutils \
cmake \
file \
git \
gmp \
isl \
libc-dev \
libtool \
make \
mpc1 \
mpfr4 \
musl-dev \
pkgconf \
zlib-dev; \
rm -rf /var/cache/apk/*

COPY --from=builder /usr/local/ /usr/
7 changes: 7 additions & 0 deletions docker/python/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM python:3.7-alpine3.12

RUN mkdir /script && \
apk update;\
apk add --no-cache bash; \
rm -rf /var/cache/apk/*
COPY ./script /script
File renamed without changes.
45 changes: 30 additions & 15 deletions src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,46 @@


class DockerConfig:
def __init__(self, cmd, dest):
timeout = 20
def __init__(self, cmd: str, dest: str):
tout = 20
self.cmd = cmd
self.dest = dest
env = os.getenv("QUART_ENV", "production")
if env == "development":
timeout = 10
self.timeout = timeout
tout = 10
self.tout = tout

def _image_name(self, name: str):
name = name.lower()
if "python" in name:
return "python-compiler"
if "c++" == name or "c" == name:
return "gcc-compiler"

return f"{name}-compiler"

@property
def data(self):
data = {
"config": {
"Image": "compiler:v1",
"Cmd": ["/bin/bash", "-c"],
"HostConfig": {"Binds": []},
},
"name": "CompilerDock",
"timeout": 0,
"name": None,
"volumes": {},
"detach": True,
"image": None,
"command": ["/bin/bash", "-c"],
"auto_remove": True,
}

data["timeout"] = self.timeout
data["config"]["Cmd"].append(self.cmd)
data["config"]["HostConfig"]["Binds"].append(f"{self.dest}:/compile")
img_name = self._image_name(self.cmd.split()[1])
data["image"] = img_name
data["name"] = f"{img_name}-container"
data["command"].append(self.cmd)
data["volumes"].update({self.dest: {"bind": "/compile", "mode": "rw"}})
return data

@property
def timeout(self):
return self.tout


class FileNames(enum.Enum):
error = "errors"
Expand All @@ -38,7 +53,7 @@ class FileNames(enum.Enum):
output = "output"


exe = {"c": " ./a.out", "c++": " ./a.out", "rust": " ./file"}
exe = {"c": " && ./a.out", "c++": " && ./a.out", "rust": " && ./file"}
lang_cmd = {
"python3": "python3",
"c": "gcc",
Expand Down
106 changes: 106 additions & 0 deletions src/utils/image_builder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import docker
from docker.errors import APIError, BuildError, ImageNotFound
from halo import Halo


class Colorize:
_colours = {
"PURPLE": "\033[95m",
"BLUE": "\033[94m",
"GREEN": "\033[92m",
"ORANGE": "\033[93m",
"RED": "\033[91m",
"ENDC": "\033[0m",
}

@classmethod
def colorize(cls, text: str, colour: str) -> str:
clr = cls._colours.get(colour.upper(), "")
end = cls._colours.get("ENDC")
return "".join([clr, text, end])


class ImageBuilder:
def __init__(self):
self.client = docker.from_env()
self.spinner = Halo(spinner="dots")
self.colorize = Colorize.colorize

def __del__(self):
if self.spinner:
self.spinner.stop()

def image_exists(self, img: str) -> bool:
try:
self.client.images.get(img)
return True
except ImageNotFound:
return False

def build_images(self, languages):
failed, built = 0, 0
for lang in languages:
try:
text_build = f"Building image for {lang}"
img_name = f"{lang}-compiler"
self.spinner.start(self.colorize(text=text_build, colour="orange"))
if self.image_exists(img_name):
self.spinner.succeed(
self.colorize(
text=f"Image {img_name} already exists, skipping build...",
colour="green",
)
)
else:
_, _ = self.client.images.build(
path="docker/",
dockerfile=f"{lang}/Dockerfile",
tag=img_name,
forcerm=True,
)
self.spinner.succeed(self.colorize(text=text_build, colour="green"))
built += 1

except APIError as apierr:
failed += 1
self.spinner.fail(self.colorize(text=apierr.explanation, colour="red"))
except BuildError as be:
failed += 1
self.spinner.fail(self.colorize(text=be.msg, colour="red"))

print(f"Built: {built}")
print(f"Failed {failed}")

def rebuild_images(self, languages):
rebuilt, failed = 0, 0
for lang in languages:
try:
text_build = f"Reuilding image for {lang}"
img_name = f"{lang}-compiler"
self.spinner.start(self.colorize(text=text_build, colour="orange"))
if self.image_exists(img_name):
self.client.images.remove(image=img_name, force=True)

_, _ = self.client.images.build(
path="docker/",
dockerfile=f"{lang}/Dockerfile",
tag=img_name,
forcerm=True,
)
self.spinner.succeed(self.colorize(text=text_build, colour="green"))
rebuilt += 1
except APIError as apierr:
failed += 1
self.spinner.fail(self.colorize(text=apierr.explanation, colour="red"))
except BuildError as be:
failed += 1
self.spinner.fail(self.colorize(text=be.msg, colour="red"))

print(f"Reuilt: {rebuilt}")
print(f"Failed {failed}")

def create_images(self, languages: list, rebuild: bool = False):
if rebuild:
self.rebuild_images(languages)
else:
self.build_images(languages)
Loading