From 105e390f6bd6439e0ac3bdaf61d2b50920b0a1fc Mon Sep 17 00:00:00 2001 From: Zeglius <33781398+Zeglius@users.noreply.github.com> Date: Wed, 22 Jan 2025 15:53:34 +0000 Subject: [PATCH] Add support for dockerfile_inline Fixes #864 Signed-off-by: Zeglius <33781398+Zeglius@users.noreply.github.com> --- examples/docker-inline/docker-compose.yml | 9 ++++ podman_compose.py | 54 ++++++++++++++++------ tests/unit/test_container_to_build_args.py | 24 ++++++++++ 3 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 examples/docker-inline/docker-compose.yml diff --git a/examples/docker-inline/docker-compose.yml b/examples/docker-inline/docker-compose.yml new file mode 100644 index 00000000..7e0655cf --- /dev/null +++ b/examples/docker-inline/docker-compose.yml @@ -0,0 +1,9 @@ +--- +version: '3' +services: + dummy: + build: + context: . + dockerfile_inline: | + FROM alpine + RUN echo "hello world" diff --git a/podman_compose.py b/podman_compose.py index a745262d..df023b61 100755 --- a/podman_compose.py +++ b/podman_compose.py @@ -25,6 +25,7 @@ import signal import subprocess import sys +import tempfile from asyncio import Task from enum import Enum @@ -2471,27 +2472,45 @@ async def compose_push(compose, args): await compose.podman.run([], "push", [cnt["image"]]) -def container_to_build_args(compose, cnt, args, path_exists): +def container_to_build_args(compose, cnt, args, path_exists, cleanup_callbacks=None): build_desc = cnt["build"] if not hasattr(build_desc, "items"): build_desc = {"context": build_desc} ctx = build_desc.get("context", ".") dockerfile = build_desc.get("dockerfile") - if dockerfile: - dockerfile = os.path.join(ctx, dockerfile) + dockerfile_inline = build_desc.get("dockerfile_inline") + if dockerfile_inline is not None: + dockerfile_inline = str(dockerfile_inline) + # Error if both `dockerfile_inline` and `dockerfile` are set + if dockerfile and dockerfile_inline: + raise OSError("dockerfile_inline and dockerfile can't be used simultaneously") + dockerfile = tempfile.NamedTemporaryFile(delete=False, suffix=".containerfile") + dockerfile.write(dockerfile_inline.encode()) + dockerfile.close() + dockerfile = dockerfile.name + + def cleanup_temp_dockfile(): + if os.path.exists(dockerfile): + os.remove(dockerfile) + + if cleanup_callbacks is not None: + list.append(cleanup_callbacks, cleanup_temp_dockfile) else: - dockerfile_alts = [ - "Containerfile", - "ContainerFile", - "containerfile", - "Dockerfile", - "DockerFile", - "dockerfile", - ] - for dockerfile in dockerfile_alts: + if dockerfile: dockerfile = os.path.join(ctx, dockerfile) - if path_exists(dockerfile): - break + else: + dockerfile_alts = [ + "Containerfile", + "ContainerFile", + "containerfile", + "Dockerfile", + "DockerFile", + "dockerfile", + ] + for dockerfile in dockerfile_alts: + dockerfile = os.path.join(ctx, dockerfile) + if path_exists(dockerfile): + break if not path_exists(dockerfile): raise OSError("Dockerfile not found in " + ctx) build_args = ["-f", dockerfile, "-t", cnt["image"]] @@ -2546,8 +2565,13 @@ async def build_one(compose, args, cnt): if img_id: return None - build_args = container_to_build_args(compose, cnt, args, os.path.exists) + cleanup_callbacks = [] + build_args = container_to_build_args( + compose, cnt, args, os.path.exists, cleanup_callbacks=cleanup_callbacks + ) status = await compose.podman.run([], "build", build_args) + for c in cleanup_callbacks: + c() return status diff --git a/tests/unit/test_container_to_build_args.py b/tests/unit/test_container_to_build_args.py index df861fb7..f06a34d2 100644 --- a/tests/unit/test_container_to_build_args.py +++ b/tests/unit/test_container_to_build_args.py @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 +import os import unittest from unittest import mock @@ -156,3 +157,26 @@ def test_caches(self): '.', ], ) + + def test_dockerfile_inline(self): + c = create_compose_mock() + + cnt = get_minimal_container() + cnt['build']['dockerfile_inline'] = "FROM busybox\nRUN echo 'hello world'" + args = get_minimal_args() + + cleanup_callbacks = [] + args = container_to_build_args( + c, cnt, args, lambda path: True, cleanup_callbacks=cleanup_callbacks + ) + + temp_dockerfile = args[args.index("-f") + 1] + self.assertTrue(os.path.exists(temp_dockerfile)) + + with open(temp_dockerfile, "rt") as file: + contents = file.read() + self.assertEqual(contents, "FROM busybox\n" + "RUN echo 'hello world'") + + for c in cleanup_callbacks: + c() + self.assertFalse(os.path.exists(temp_dockerfile))