daggerml.contrib.funks

View source
 1from __future__ import annotations
 2
 3from daggerml.contrib import api
 4
 5
 6def _run(*cmd: str) -> None:
 7    import subprocess
 8
 9    from daggerml.api import DmlRepoError
10
11    proc = subprocess.run(cmd, check=False)
12    if proc.returncode == 0:
13        return
14    raise DmlRepoError(
15        f"Command failed (exit code {proc.returncode}): {' '.join(cmd)}. See the execution logs for command output."
16    )
17
18
19def _gzip_file(source: str, destination: str) -> None:
20    import gzip
21    import shutil
22
23    with open(source, "rb") as src, gzip.open(destination, "wb") as dst:
24        shutil.copyfileobj(src, dst)
25
26
27def _remove_docker_image(image: str) -> None:
28    import subprocess
29
30    subprocess.run(("docker", "image", "rm", image), check=False, capture_output=True, text=True)
31
32
33@api.funkify(uri="script", adapter="local", extra_objs=(_run, _gzip_file, _remove_docker_image))
34def docker_build(dag, context_tarball, build_flags=(), repo=None):
35    from contextlib import chdir
36    from tempfile import TemporaryDirectory
37    from uuid import uuid4
38
39    from daggerml import Uri
40    from daggerml.contrib.executors.docker import _image_lock
41    from daggerml.contrib.s3 import S3Store
42
43    build_flags = tuple(build_flags.value())
44
45    store = S3Store()
46    tag = uuid4().hex
47    local_image = f"daggerml-archive:{tag}"
48    with TemporaryDirectory(prefix="dml-docker-build-") as build_dir:
49        store.untar(context_tarball.value(), build_dir)
50        with chdir(build_dir):
51            repo = repo.value() if repo is not None else None
52            image_tar = "./image.tar"
53            with _image_lock():
54                try:
55                    _run("docker", "build", *build_flags, "-t", local_image, ".")
56                    if repo is not None:
57                        remote_image = f"{repo.uri}:{tag}"
58                        try:
59                            _run("docker", "tag", local_image, remote_image)
60                            _run("docker", "push", remote_image)
61                        finally:
62                            _remove_docker_image(remote_image)
63                    else:
64                        _run("docker", "save", "-o", str(image_tar), local_image)
65                finally:
66                    _remove_docker_image(local_image)
67            if repo is not None:
68                return dag.put(Uri(remote_image), name="remote-image")
69            compressed_image_tar = "./image.tar.gz"
70            _gzip_file(image_tar, compressed_image_tar)
71            return store.put(filepath=compressed_image_tar, suffix=".tar.gz")
72
73
74__all__ = ["docker_build"]

docker_build

docker_build= DelayedRunnable(uri='script', adapter='local', sub=None, kwargs={'fn': <function docker_build>, 'extra_objs': (<function _run>, <function _gzip_file>, <function _remove_docker_image>), 'script': 'def _run(*cmd: str) -> None:\n import subprocess\n from daggerml.api import DmlRepoError\n proc = subprocess.run(cmd, check=False)\n if proc.returncode == 0:\n return\n raise DmlRepoError(f"Command failed (exit code {proc.returncode}): {\' \'.join(cmd)}. See the execution logs for command output.")\n\ndef _gzip_file(source: str, destination: str) -> None:\n import gzip\n import shutil\n with open(source, \'rb\') as src, gzip.open(destination, \'wb\') as dst:\n shutil.copyfileobj(src, dst)\n\ndef _remove_docker_image(image: str) -> None:\n import subprocess\n subprocess.run((\'docker\', \'image\', \'rm\', image), check=False, capture_output=True, text=True)\n\ndef docker_build(dag, context_tarball, build_flags=(), repo=None):\n from contextlib import chdir\n from tempfile import TemporaryDirectory\n from uuid import uuid4\n from daggerml import Uri\n from daggerml.contrib.executors.docker import _image_lock\n from daggerml.contrib.s3 import S3Store\n build_flags = tuple(build_flags.value())\n store = S3Store()\n tag = uuid4().hex\n local_image = f\'daggerml-archive:{tag}\'\n with TemporaryDirectory(prefix=\'dml-docker-build-\') as build_dir:\n store.untar(context_tarball.value(), build_dir)\n with chdir(build_dir):\n repo = repo.value() if repo is not None else None\n image_tar = \'./image.tar\'\n with _image_lock():\n try:\n _run(\'docker\', \'build\', *build_flags, \'-t\', local_image, \'.\')\n if repo is not None:\n remote_image = f\'{repo.uri}:{tag}\'\n try:\n _run(\'docker\', \'tag\', local_image, remote_image)\n _run(\'docker\', \'push\', remote_image)\n finally:\n _remove_docker_image(remote_image)\n else:\n _run(\'docker\', \'save\', \'-o\', str(image_tar), local_image)\n finally:\n _remove_docker_image(local_image)\n if repo is not None:\n return dag.put(Uri(remote_image), name=\'remote-image\')\n compressed_image_tar = \'./image.tar.gz\'\n _gzip_file(image_tar, compressed_image_tar)\n return store.put(filepath=compressed_image_tar, suffix=\'.tar.gz\')', 'fn_name': 'docker_build'})