Skip to content

Commit

Permalink
changed docker build so that prints outputs to stdout by default of l…
Browse files Browse the repository at this point in the history
…oglevel <= INFO
  • Loading branch information
tclose committed Oct 18, 2024
1 parent 9d387dc commit 16016c0
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 17 deletions.
2 changes: 1 addition & 1 deletion conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from frametree.testing import TestAxes, MockRemote, AlternateMockRemote
from frametree.common import FileSystem

log_level = logging.WARNING
log_level = logging.INFO

logger = logging.getLogger("pipeline2app")
logger.setLevel(log_level)
Expand Down
66 changes: 50 additions & 16 deletions pipeline2app/core/image/base.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
from __future__ import annotations
import typing as ty

# import hashlib
from pathlib import PurePath, Path
import json
import re
import tempfile
import itertools
import logging
from copy import copy
import shutil
from inspect import isclass, isfunction
from build import ProjectBuilder
import attrs
import docker
import docker.errors
from neurodocker.reproenv import DockerRenderer
from pipeline2app.core import __version__
from pipeline2app.core import PACKAGE_NAME
Expand Down Expand Up @@ -109,8 +109,9 @@ def make(
"""

if build_dir is None:
build_dir = tempfile.mkdtemp()
build_dir = Path(build_dir)
build_dir = Path(tempfile.mkdtemp())
elif not isinstance(build_dir, Path):
build_dir = Path(build_dir)
if build_dir.exists():
shutil.rmtree(build_dir)
build_dir.mkdir()
Expand Down Expand Up @@ -209,7 +210,8 @@ def build(
build_dir: Path,
image_tag: str,
no_cache: bool = False,
) -> None:
stream_output: ty.Optional[bool] = None,
) -> str:
"""Builds the dockerfile in the specified build directory
Parameters
Expand All @@ -222,8 +224,23 @@ def build(
Docker image tag to assign to the built image
no_cache : bool, optional
whether to cache the build layers or not, by default False
"""
stream_output : bool, optional
whether to stream the output of the build process to stdout as it is being
built. If None, the output will be streamed if the logger level is set to
INFO or lower, by default None
Returns
-------
str
the image ID of the built image
Raises
------
docker.errors.BuildError
If the build process fails
"""
if stream_output is None:
stream_output = logger.level <= logging.INFO
# Save generated dockerfile to file
out_file = build_dir / "Dockerfile"
out_file.parent.mkdir(exist_ok=True, parents=True)
Expand All @@ -232,15 +249,32 @@ def build(
logger.info("Dockerfile for '%s' generated at %s", image_tag, str(out_file))

dc = docker.from_env()
try:
dc.images.build(path=str(build_dir), tag=image_tag, nocache=no_cache)
except docker.errors.BuildError as e:
build_log = "\n".join(ln.get("stream", "") for ln in e.build_log)
raise RuntimeError(
f"Building '{image_tag}' from '{str(build_dir)}/Dockerfile' "
f"failed with the following errors:\n\n{build_log}"
)
logging.info("Successfully built docker image %s", image_tag)

response = dc.api.build(
path=str(build_dir.absolute()), tag=image_tag, rm=True, decode=True
)
last_event = None
result_stream, progress_stream = itertools.tee(response)
for chunk in progress_stream:
if "stream" in chunk:
if stream_output:
print(chunk["stream"], end="")
match = re.search(
r"(^Successfully built |sha256:)([0-9a-f]+)$", chunk["stream"]
)
if match:
logging.info("Successfully built docker image %s", image_tag)
return match.group(2)
if "error" in chunk:
raise docker.errors.BuildError(
chunk["error"],
(
f"Building '{image_tag}' from '{str(build_dir)}/Dockerfile': "
+ str(result_stream)
),
)
last_event = chunk
raise docker.errors.BuildError(last_event or "Unknown", result_stream)

def init_dockerfile(self) -> DockerRenderer:
dockerfile = DockerRenderer(self.base_image.package_manager).from_(
Expand Down

0 comments on commit 16016c0

Please sign in to comment.