mirror of
https://github.com/d9pouces/id_configurator.git
synced 2026-11-09 01:47:21 +01:00
feat: new configurations for APK/Java/Python/Yum
Signed-off-by: d9pouces <github@19pouces.net>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
import logging
|
||||
|
||||
import typer
|
||||
|
||||
from id_tools.build import app as build_app
|
||||
|
||||
SUCCESS = 25
|
||||
|
||||
|
||||
class ColorFormatter(logging.Formatter):
|
||||
"""Logging formatter that adds ANSI color codes based on log level."""
|
||||
|
||||
RESET = "\033[0m"
|
||||
COLORS = {
|
||||
logging.DEBUG: "\033[90m", # gris
|
||||
logging.INFO: "\033[34m", # bleu
|
||||
SUCCESS: "\033[32m", # vert
|
||||
logging.WARNING: "\033[33m", # orange
|
||||
logging.ERROR: "\033[31m", # rouge
|
||||
logging.CRITICAL: "\033[1;31m", # rouge gras
|
||||
}
|
||||
|
||||
def format(self, record):
|
||||
color = self.COLORS.get(record.levelno, self.RESET)
|
||||
message = super().format(record)
|
||||
return f"{color}{message}{self.RESET}"
|
||||
|
||||
|
||||
def setup_logging():
|
||||
handler = logging.StreamHandler()
|
||||
handler.setFormatter(ColorFormatter("%(message)s"))
|
||||
logging.root.addHandler(handler)
|
||||
logging.root.setLevel(logging.INFO)
|
||||
|
||||
|
||||
app = typer.Typer()
|
||||
|
||||
|
||||
@app.callback()
|
||||
def main():
|
||||
setup_logging()
|
||||
|
||||
|
||||
app.add_typer(build_app, name="build")
|
||||
if __name__ == "__main__":
|
||||
app()
|
||||
@@ -0,0 +1,177 @@
|
||||
import logging
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
import typer
|
||||
|
||||
from id_tools.config import SourceConfig
|
||||
|
||||
app = typer.Typer(help="Build utilities for JS/CSS files and emails templates")
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# noinspection SpellCheckingInspection
|
||||
DOCKER_FILE_BUILDER = r"""# This file is part of Interdiode
|
||||
# Copyright (c) {build_year} InterDiode <contact@mail.interdiode.fr>
|
||||
# All Rights Reserved
|
||||
########################################################################################################################
|
||||
# This file is generated by id_tools/build.py. Do not edit it manually.
|
||||
########################################################################################################################
|
||||
FROM dhi.io/python:{python_version}-{docker_version} AS interdiode-base
|
||||
########################################################################################################################
|
||||
# generate the package and download required some tools in a first image
|
||||
########################################################################################################################
|
||||
FROM interdiode-base AS interdiode-builder
|
||||
ENV{docker_env}
|
||||
USER root
|
||||
RUN mkdir -p /src /usr/local/interdiode
|
||||
RUN chown -R {docker_user}:{docker_group} /src /usr/local/interdiode
|
||||
COPY ./pyproject.toml /src/pyproject.toml
|
||||
COPY ./README.md /src/README.md
|
||||
COPY ./LICENSE /src/LICENSE
|
||||
COPY ./id_configurator /src/id_configurator
|
||||
COPY ./tests /src/tests
|
||||
RUN chown -R {docker_user}:{docker_group} /src
|
||||
USER {docker_user}
|
||||
RUN python3 -m pip install --user pip uv --upgrade
|
||||
WORKDIR /src
|
||||
RUN python3 -m uv build
|
||||
"""
|
||||
# noinspection SpellCheckingInspection
|
||||
DOCKER_FILE_INSTALL = r"""
|
||||
########################################################################################################################
|
||||
# install the package without the build dependencies
|
||||
########################################################################################################################
|
||||
FROM interdiode-base AS interdiode-install
|
||||
ENV{docker_env}
|
||||
COPY --from=interdiode-builder /src/dist /tmp/dist
|
||||
RUN apt-get update
|
||||
RUN DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confnew" --allow-downgrades --allow-remove-essential --allow-unauthenticated -fuy dist-upgrade
|
||||
RUN DEBIAN_FRONTEND=noninteractive apt-get install --yes -qq --no-install-recommends build-essential
|
||||
RUN mkdir -p /src/build /chroot/usr/local/bin /usr/local/interdiode \
|
||||
&& chown -R {docker_user}:{docker_group} /usr/local/interdiode /tmp/dist
|
||||
USER {docker_user}
|
||||
RUN /bin/sh -c "python3 -m pip install --user /tmp/dist/*.whl"
|
||||
"""
|
||||
# noinspection SpellCheckingInspection
|
||||
DOCKER_FILE_RUNTIME = r"""########################################################################################################################
|
||||
# copy the installed packages
|
||||
########################################################################################################################
|
||||
FROM interdiode-base AS interdiode-runtime
|
||||
ENV{docker_env}
|
||||
LABEL org.opencontainers.image.authors="contact@mail.interdiode.fr"
|
||||
LABEL org.opencontainers.image.created="{build_date}"
|
||||
LABEL org.opencontainers.image.description="Air gap made simple!"
|
||||
LABEL org.opencontainers.image.documentation="{documentation_url}"
|
||||
LABEL org.opencontainers.image.licenses="LicenseRef-InterDiode-Commercial-1.0"
|
||||
LABEL org.opencontainers.image.revision="{vcs_revision}"
|
||||
LABEL org.opencontainers.image.title="InterDiode Configurator"
|
||||
LABEL org.opencontainers.image.url="{interdiode_url}"
|
||||
LABEL org.opencontainers.image.vendor="InterDiode"
|
||||
LABEL org.opencontainers.image.version="{id_configurator_version}"
|
||||
LABEL description="Air gap made simple!"
|
||||
COPY --from=interdiode-install --chown=0:0 /chroot/usr/local/bin /usr/local/bin
|
||||
COPY --from=interdiode-install /usr/local/interdiode /usr/local/interdiode
|
||||
RUN DEBIAN_FRONTEND=noninteractive mkdir -p /usr/local/interdiode \
|
||||
&& chown -R {docker_user}:{docker_group} /usr/local/interdiode
|
||||
COPY ./LICENSE /chroot/licenses/LICENSE
|
||||
COPY ./LICENSE /chroot/usr/share/doc/interdiode/LICENSE
|
||||
WORKDIR /
|
||||
"""
|
||||
|
||||
NPM_TO_COPY = [
|
||||
("bootstrap/dist/js/bootstrap.esm.js.map", "js/bootstrap.esm.js.map"),
|
||||
]
|
||||
|
||||
|
||||
def build_docker_image(
|
||||
config: SourceConfig,
|
||||
registry: str | None = None,
|
||||
platform: str = "linux/amd64",
|
||||
push: bool = False,
|
||||
) -> bool:
|
||||
"""Build the Docker image."""
|
||||
if push and not registry:
|
||||
raise ValueError("--push requires --registry to be set.")
|
||||
id_configurator_version = config.get_project_version()
|
||||
values = config.get_parameters()
|
||||
package_build = DOCKER_FILE_BUILDER.format(**values)
|
||||
v_tag = f"id_configurator:{id_configurator_version}"
|
||||
l_tag = "id_configurator:latest"
|
||||
image_install = DOCKER_FILE_INSTALL.format(**values)
|
||||
image_build = DOCKER_FILE_RUNTIME.format(**values)
|
||||
with (
|
||||
tempfile.NamedTemporaryFile(
|
||||
mode="w", delete=True, prefix="Dockerfile.", suffix=".package"
|
||||
) as fd,
|
||||
):
|
||||
fd.write(package_build)
|
||||
fd.write(image_install)
|
||||
fd.write(image_build)
|
||||
fd.flush()
|
||||
# noinspection SpellCheckingInspection
|
||||
cmd = [
|
||||
"docker",
|
||||
"buildx",
|
||||
"build",
|
||||
"--no-cache",
|
||||
"--attest",
|
||||
"type=provenance,mode=max,version=v1",
|
||||
"--attest",
|
||||
"type=sbom",
|
||||
"--platform",
|
||||
platform,
|
||||
"-f",
|
||||
fd.name,
|
||||
]
|
||||
if registry:
|
||||
cmd += ["-t", f"{registry}/{v_tag}", "-t", f"{registry}/{l_tag}"]
|
||||
else:
|
||||
cmd += ["-t", f"{registry}/{v_tag}", "-t", f"{registry}/{l_tag}"]
|
||||
if push and registry:
|
||||
cmd.insert(3, "--push")
|
||||
cmd.append(".")
|
||||
try:
|
||||
typer.echo(f"Building Docker image {v_tag} for platform {platform}...")
|
||||
typer.echo(" ".join(cmd))
|
||||
subprocess.check_call(cmd, cwd=config.source_dir)
|
||||
except subprocess.CalledProcessError:
|
||||
print(package_build + image_install + image_build)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# noinspection SpellCheckingInspection
|
||||
@app.command(name="docker", help="Build the Docker image.")
|
||||
def docker_image(
|
||||
registry: str = typer.Option(
|
||||
"interdiode", help="The registry to publish the Docker image to."
|
||||
),
|
||||
platform: str = typer.Option(
|
||||
"linux/amd64", help="Platform(s) of the Docker image."
|
||||
),
|
||||
docker_version: str = typer.Option(
|
||||
"debian13-dev", help="Version of the base Docker image."
|
||||
),
|
||||
push: bool = typer.Option(
|
||||
False, "--push", help="Push the built image(s) to the registry."
|
||||
),
|
||||
docker_login: str = typer.Option(
|
||||
"", envvar="DOCKER_HUB_LOGIN", help="Nom d'utilisateur Docker"
|
||||
),
|
||||
docker_token: str = typer.Option(
|
||||
"", envvar="DOCKER_HUB_TOKEN", help="Jeton d'accès Docker"
|
||||
),
|
||||
):
|
||||
config = SourceConfig(docker_version)
|
||||
if docker_login and docker_token:
|
||||
cmd = ["docker", "login", "-u", docker_login, "--password-stdin"]
|
||||
subprocess.run(
|
||||
cmd, input=docker_token, text=True, check=True, cwd=config.source_dir
|
||||
)
|
||||
|
||||
success = build_docker_image(
|
||||
config, registry=registry, platform=platform, push=push
|
||||
)
|
||||
if not success:
|
||||
raise typer.Exit(code=1)
|
||||
@@ -0,0 +1,72 @@
|
||||
import datetime
|
||||
import pathlib
|
||||
import re
|
||||
import subprocess
|
||||
import tomllib
|
||||
|
||||
|
||||
class SourceConfig:
|
||||
site_url = "https://interdiode.fr/"
|
||||
documentation_url = "https://interdiode.fr/static/latest/index.html"
|
||||
cosign_key_url = "https://interdiode.fr/static/cosign.interdiode.fr.pub"
|
||||
docker_user = "nonroot"
|
||||
docker_group = "nonroot"
|
||||
# noinspection SpellCheckingInspection
|
||||
docker_env = """ PATH=/usr/local/bin/:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/interdiode/bin \
|
||||
PIP_DISABLE_PIP_VERSION_CHECK=on \
|
||||
PIP_NO_CACHE_DIR=on \
|
||||
PYTHONUSERBASE=/usr/local/interdiode \
|
||||
PYTHONFAULTHANDLER=1 \
|
||||
PYTHONHASHSEED=random \
|
||||
PYTHONUNBUFFERED=1
|
||||
"""
|
||||
|
||||
# noinspection SpellCheckingInspection
|
||||
def __init__(self, docker_version: str = "debian13-dev"):
|
||||
self.source_dir = pathlib.Path(__file__).parent.parent
|
||||
with open(self.source_dir / "pyproject.toml", "rb") as fd:
|
||||
self.raw_metadata = tomllib.load(fd)
|
||||
self.docker_version = docker_version
|
||||
|
||||
def get_python_versions(self) -> list[str]:
|
||||
"""Return the list of Python versions supported by the project."""
|
||||
python_versions = []
|
||||
for classifier in self.raw_metadata["project"]["classifiers"]:
|
||||
if matcher := re.match(
|
||||
r"Programming Language :: Python :: (\d\.\d+)", classifier
|
||||
):
|
||||
python_versions.append(matcher.group(1))
|
||||
return python_versions
|
||||
|
||||
def get_project_version(self) -> str:
|
||||
"""Get the version of InterDiode from the pyproject.toml file."""
|
||||
return self.raw_metadata["project"]["version"]
|
||||
|
||||
def get_git_project_revision(self) -> str:
|
||||
"""Get the git revision of the project."""
|
||||
out = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=self.source_dir) # nosec B607
|
||||
return out.decode().strip()
|
||||
|
||||
def get_parameters(self, python_version: str | None = None) -> dict[str, str]:
|
||||
python_version = python_version or self.get_python_versions()[-1]
|
||||
return {
|
||||
"build_date": datetime.datetime.now(tz=datetime.UTC).isoformat(),
|
||||
"build_year": str(datetime.datetime.now(tz=datetime.UTC).year),
|
||||
"docker_env": self.docker_env,
|
||||
"docker_user": self.docker_user,
|
||||
"docker_group": self.docker_group,
|
||||
"docker_version": self.docker_version,
|
||||
"documentation_url": self.documentation_url,
|
||||
"interdiode_url": self.site_url,
|
||||
"id_configurator_version": self.get_project_version(),
|
||||
"python_version": python_version,
|
||||
"vcs_revision": self.get_git_project_revision(),
|
||||
}
|
||||
|
||||
def get_project_author_and_emails(self) -> list[dict[str, str]]:
|
||||
"""Get the authors of InterDiode from the pyproject.toml file."""
|
||||
return self.raw_metadata["project"]["authors"]
|
||||
|
||||
def get_project_authors(self) -> list[str]:
|
||||
"""Get the authors of InterDiode from the pyproject.toml file."""
|
||||
return [author["name"] for author in self.raw_metadata["project"]["authors"]]
|
||||
Reference in New Issue
Block a user