Add support for dockerfile_inline

Fixes #864

Signed-off-by: Zeglius <33781398+Zeglius@users.noreply.github.com>
This commit is contained in:
Zeglius 2025-01-22 15:53:34 +00:00 committed by Povilas Kanapickas
parent d79ff01e77
commit 105e390f6b
3 changed files with 72 additions and 15 deletions

View File

@ -0,0 +1,9 @@
---
version: '3'
services:
dummy:
build:
context: .
dockerfile_inline: |
FROM alpine
RUN echo "hello world"

View File

@ -25,6 +25,7 @@ import shlex
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

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
import os
import unittest
from unittest import mock
@ -156,3 +157,26 @@ class TestContainerToBuildArgs(unittest.TestCase):
'.',
],
)
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))