• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pantsbuild / pants / 22360764254

24 Feb 2026 04:46PM UTC coverage: 88.798% (-4.1%) from 92.935%
22360764254

Pull #23133

github

web-flow
Merge 4c056364c into 4d038bd74
Pull Request #23133: Add buildctl engine

181 of 264 new or added lines in 8 files covered. (68.56%)

3184 existing lines in 145 files now uncovered.

77555 of 87339 relevant lines covered (88.8%)

3.34 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

79.75
/src/python/pants/backend/docker/subsystems/docker_options.py
1
# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from __future__ import annotations
7✔
5

6
import logging
7✔
7
import sys
7✔
8
from typing import Any
7✔
9

10
from pants.backend.docker.engine_types import DockerBuildEngine, DockerEngines, DockerRunEngine
7✔
11
from pants.backend.docker.package_types import DockerPushOnPackageBehavior
7✔
12
from pants.backend.docker.registries import DockerRegistries
7✔
13
from pants.core.util_rules.search_paths import ExecutableSearchPathsOptionMixin
7✔
14
from pants.option.option_types import (
7✔
15
    BoolOption,
16
    DataclassOption,
17
    DictOption,
18
    EnumOption,
19
    ShellStrListOption,
20
    StrListOption,
21
    StrOption,
22
    WorkspacePathOption,
23
)
24
from pants.option.subsystem import Subsystem
7✔
25
from pants.util.docutil import bin_name
7✔
26
from pants.util.memo import memoized_method
7✔
27
from pants.util.strutil import bullet_list, softwrap
7✔
28

29
doc_links = {
7✔
30
    "docker_env_vars": (
31
        "https://docs.docker.com/engine/reference/commandline/cli/#environment-variables"
32
    ),
33
}
34

35
logger = logging.getLogger(__name__)
7✔
36

37

38
class DockerOptions(Subsystem):
7✔
39
    options_scope = "docker"
7✔
40
    help = "Options for interacting with Docker."
7✔
41

42
    class EnvironmentAware(ExecutableSearchPathsOptionMixin, Subsystem.EnvironmentAware):
7✔
43
        _env_vars = ShellStrListOption(
7✔
44
            help=softwrap(
45
                """
46
                Environment variables to set for `docker` invocations.
47

48
                Entries are either strings in the form `ENV_VAR=value` to set an explicit value;
49
                or just `ENV_VAR` to copy the value from Pants's own environment.
50
                """
51
            ),
52
            advanced=True,
53
        )
54
        executable_search_paths_help = softwrap(
7✔
55
            """
56
            The PATH value that will be used to find the Docker client and any tools required.
57
            """
58
        )
59

60
        @property
7✔
61
        def env_vars(self) -> tuple[str, ...]:
7✔
62
            return tuple(sorted(set(self._env_vars)))
2✔
63

64
    _registries = DictOption[Any](
65
        help=softwrap(
66
            """
67
            Configure Docker registries. The schema for a registry entry is as follows:
68

69
                {
70
                    "registry-alias": {
71
                        "address": "registry-domain:port",
72
                        "default": bool,
73
                        "extra_image_tags": [],
74
                        "skip_push": bool,
75
                        "repository": str,
76
                        "use_local_alias": bool,
77
                    },
78
                    ...
79
                }
80

81
            If no registries are provided in a `docker_image` target, then all default
82
            addresses will be used, if any.
83

84
            The `docker_image.registries` may be provided with a list of registry addresses
85
            and registry aliases prefixed with `@` to be used instead of the defaults.
86

87
            A configured registry is marked as default either by setting `default = true`
88
            or with an alias of `"default"`.
89

90
            A `docker_image` may be pushed to a subset of registries using the per registry
91
            `skip_push` option rather then the all or nothing toggle of the field option `skip_push`
92
            on the `docker_image` target.
93

94
            Any image tags that should only be added for specific registries may be provided as the
95
            `extra_image_tags` option. The tags may use value formatting the same as for the
96
            `image_tags` field of the `docker_image` target.
97

98
            When a registry provides a `repository` value, it will be used instead of the
99
            `docker_image.repository` or the default repository. Using the placeholders
100
            `{target_repository}` or `{default_repository}` those overridden values may be
101
            incorporated into the registry specific repository value.
102

103
            If `use_local_alias` is true, a built image is additionally tagged locally using the
104
            registry alias as the value for repository (i.e. the additional image tag is not pushed)
105
            and will be used for any `pants run` requests.
106
            """
107
        ),
108
        fromfile=True,
109
    )
110
    default_repository = StrOption(
7✔
111
        help=softwrap(
112
            f"""
113
            Configure the default repository name used in the Docker image tag.
114

115
            The value is formatted and may reference these variables (in addition to the normal
116
            placeholders derived from the Dockerfile and build args etc):
117

118
            {bullet_list(["name", "directory", "parent_directory", "full_directory", "target_repository"])}
119

120
            Example: `--default-repository="{{directory}}/{{name}}"`.
121

122
            The `name` variable is the `docker_image`'s target name.
123

124
            With the directory variables available, given a sample repository path of `baz/foo/bar/BUILD`,
125
            then `directory` is `bar`, `parent_directory` is `foo` and `full_directory` will be `baz/foo/bar`.
126

127
            Use the `repository` field to set this value directly on a `docker_image` target.
128

129
            Registries may override the repository value for a specific registry.
130

131
            Any registries or tags are added to the image name as required, and should
132
            not be part of the repository name.
133
            """
134
        ),
135
        default="{name}",
136
    )
137
    default_context_root = WorkspacePathOption(
7✔
138
        default="",
139
        help=softwrap(
140
            """
141
            Provide a default Docker build context root path for `docker_image` targets that
142
            does not specify their own `context_root` field.
143

144
            The context root is relative to the build root by default, but may be prefixed
145
            with `./` to be relative to the directory of the BUILD file of the `docker_image`.
146

147
            Examples:
148

149
                --default-context-root=src/docker
150
                --default-context-root=./relative_to_the_build_file
151
            """
152
        ),
153
    )
154
    global_options = ShellStrListOption(
7✔
155
        default=[],
156
        help=softwrap(
157
            """
158
            Global options to use for all Docker and BuildKit invocations.
159
            """
160
        ),
161
    )
162
    engine = DataclassOption(
7✔
163
        default=DockerEngines(),
164
        mutually_exclusive_group="engines",
165
        help=softwrap(
166
            """
167
        The engines to use for Docker builds and runs.
168

169
        Valid values for `build` are:
170

171
        - `docker`: Use the Docker CLI to build images. (https://docs.docker.com/reference/cli/docker/buildx/build/)
172
        - `buildkit`: Invoke buildkit directly to build images. (https://github.com/moby/buildkit/blob/master/docs/reference/buildctl.md#build)
173
        - `podman`: Use Podman to build images. (https://docs.podman.io/en/latest/markdown/podman-build.1.html)
174

175
        Valid values for `run` are:
176

177
        - `docker`: Use the Docker CLI to run containers. (https://docs.docker.com/reference/cli/docker/run/)
178
        - `podman`: Use Podman to run containers. (https://docs.podman.io/en/latest/markdown/podman-run.1.html)
179
        """
180
        ),
181
    )
182
    use_buildx = BoolOption(
7✔
183
        default=True,
184
        help=softwrap(
185
            """
186
            DEPRECATED: Use [docker.engine].build = "docker" instead.
187

188
            See here for using the legacy builder: https://docs.docker.com/reference/cli/docker/build-legacy/
189

190
            Use [buildx](https://github.com/docker/buildx#buildx) (and BuildKit) for builds.
191
            """
192
        ),
193
        deprecation_start_version="2.31.0",
194
        mutually_exclusive_group="engines",
195
    )
196

197
    @property
7✔
198
    def build_engine(self) -> DockerBuildEngine:
7✔
199
        use_buildx = self.options.get("use_buildx")
2✔
200
        if use_buildx is not None:
2✔
201
            warning = '`[docker].use_buildx` is deprecated. Buildx is now the default Docker build engine. Use `[docker.engine].build = "docker"` instead.'
2✔
202
            if not use_buildx:
2✔
NEW
203
                warning += (
×
204
                    " To use the legacy engine, add `DOCKER_BUILDKIT=0` to `[docker].env_vars`."
205
                )
206
            logger.warning(warning)
2✔
207
            return DockerBuildEngine.DOCKER
2✔
NEW
208
        experimental_enable_podman = self.options.get("experimental_enable_podman")
×
NEW
209
        if experimental_enable_podman is not None:
×
NEW
210
            logger.warning(
×
211
                '`[docker].experimental_enable_podman` is deprecated. Use `[docker.engine].build = "podman"` instead.'
212
            )
NEW
213
            return (
×
214
                DockerBuildEngine.PODMAN if experimental_enable_podman else DockerBuildEngine.DOCKER
215
            )
NEW
216
        return self.engine.build
×
217

218
    @property
7✔
219
    def run_engine(self) -> DockerRunEngine:
7✔
NEW
220
        experimental_enable_podman = self.options.get("experimental_enable_podman", None)
×
NEW
221
        match experimental_enable_podman:
×
NEW
222
            case None:
×
NEW
223
                return self.engine.run
×
UNCOV
224
            case True:
×
UNCOV
225
                engine = DockerRunEngine.PODMAN
×
UNCOV
226
            case False:
×
UNCOV
227
                engine = DockerRunEngine.DOCKER
×
UNCOV
228
        logger.warning(
×
229
            f'`[docker].experimental_enable_podman` is deprecated. Use `[docker.engine].run = "{engine.value}"` instead.'
230
        )
UNCOV
231
        return engine
×
232

233
    _build_args = ShellStrListOption(
7✔
234
        help=softwrap(
235
            f"""
236
            Global build arguments (for Docker `--build-arg` options) to use for all
237
            `docker build` invocations.
238

239
            Entries are either strings in the form `ARG_NAME=value` to set an explicit value;
240
            or just `ARG_NAME` to copy the value from Pants's own environment.
241

242
            Example:
243

244
                [{options_scope}]
245
                build_args = ["VAR1=value", "VAR2"]
246

247

248
            Use the `extra_build_args` field on a `docker_image` target for additional
249
            image specific build arguments.
250
            """
251
        ),
252
    )
253
    build_target_stage = StrOption(
7✔
254
        default=None,
255
        help=softwrap(
256
            """
257
            Global default value for `target_stage` on `docker_image` targets, overriding
258
            the field value on the targets, if there is a matching stage in the `Dockerfile`.
259

260
            This is useful to provide from the command line, to specify the target stage to
261
            build for at execution time.
262
            """
263
        ),
264
    )
265
    build_hosts = DictOption[str](
7✔
266
        default={},
267
        help=softwrap(
268
            f"""
269
            Hosts entries to be added to the `/etc/hosts` file in all built images.
270

271
            Example:
272

273
                [{options_scope}]
274
                build_hosts = {{"docker": "10.180.0.1", "docker2": "10.180.0.2"}}
275

276
            Use the `extra_build_hosts` field on a `docker_image` target for additional
277
            image specific host entries.
278
            """
279
        ),
280
    )
281
    build_no_cache = BoolOption(
7✔
282
        default=False,
283
        help="Do not use the Docker cache when building images.",
284
    )
285
    build_verbose = BoolOption(
7✔
286
        default=False,
287
        help="Whether to log the Docker output to the console. If false, only the image ID is logged.",
288
    )
289
    run_args = ShellStrListOption(
7✔
290
        default=["--interactive", "--tty"] if sys.stdout.isatty() else [],
291
        help=softwrap(
292
            f"""
293
            Additional arguments to use for `docker run` invocations.
294

295
            Example:
296

297
                $ {bin_name()} run --{options_scope}-run-args="-p 127.0.0.1:80:8080/tcp\
298
                    --name demo" src/example:image -- [image entrypoint args]
299

300
            To provide the top-level options to the `docker` client, use
301
            `[{options_scope}].env_vars` to configure the
302
            [Environment variables]({doc_links["docker_env_vars"]}) as appropriate.
303

304
            The arguments for the image entrypoint may be passed on the command line after a
305
            double dash (`--`), or using the `--run-args` option.
306

307
            Defaults to `--interactive --tty` when stdout is connected to a terminal.
308
            """
309
        ),
310
    )
311
    publish_noninteractively = BoolOption(
7✔
312
        default=False,
313
        help=softwrap(
314
            """
315
            If true, publish images non-interactively. This allows for pushes to be parallelized, but requires
316
            docker to be pre-authenticated to the registries to which it is pushing.
317
            """
318
        ),
319
    )
320
    _tools = StrListOption(
7✔
321
        default=[],
322
        help=softwrap(
323
            """
324
            List any additional executable tools required for Docker to work. The paths to
325
            these tools will be included in the PATH used in the execution sandbox, so that
326
            they may be used by the Docker client.
327
            """
328
        ),
329
        advanced=True,
330
    )
331

332
    _optional_tools = StrListOption(
7✔
333
        help=softwrap(
334
            """
335
            List any additional executables which are not mandatory for Docker to work, but which
336
            should be included if available. The paths to these tools will be included in the
337
            PATH used in the execution sandbox, so that they may be used by the Docker client.
338
            """
339
        ),
340
        advanced=True,
341
    )
342

343
    tailor = BoolOption(
7✔
344
        default=True,
345
        help="If true, add `docker_image` targets with the `tailor` goal.",
346
        advanced=True,
347
    )
348

349
    suggest_renames = BoolOption(
7✔
350
        default=True,
351
        help=softwrap(
352
            """
353
            When true and, the `docker_image` build fails, enrich the logs with suggestions
354
            for renaming source file COPY instructions where possible.
355
            """
356
        ),
357
        advanced=True,
358
    )
359

360
    push_on_package = EnumOption(
7✔
361
        default=DockerPushOnPackageBehavior.WARN,
362
        help=softwrap(
363
            """
364
            The behavior when a docker_image target would push to a registry during packaging
365
            (e.g., when output has push=true or type=registry).
366

367
            Options:
368
            - allow: Allow pushes during packaging
369
            - warn: Log a warning but continue with the push (default)
370
            - ignore: Skip building images that would push
371
            - error: Raise an error if an image would push
372
            """
373
        ),
374
    )
375

376
    @property
7✔
377
    def build_args(self) -> tuple[str, ...]:
7✔
378
        return tuple(sorted(set(self._build_args)))
4✔
379

380
    @property
7✔
381
    def tools(self) -> tuple[str, ...]:
7✔
382
        return tuple(sorted(set(self._tools)))
2✔
383

384
    @property
7✔
385
    def optional_tools(self) -> tuple[str, ...]:
7✔
386
        return tuple(sorted(set(self._optional_tools)))
2✔
387

388
    @memoized_method
7✔
389
    def registries(self) -> DockerRegistries:
7✔
390
        return DockerRegistries.from_dict(self._registries)
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc