Skip to content

Commit

Permalink
[internal] Rollout more Options V2 options! (pantsbuild#14444)
Browse files Browse the repository at this point in the history
[internal] Rollout more Options V2 options! 

[ci skip-rust]
[ci skip-build-wheels]
  • Loading branch information
thejcannon authored Feb 12, 2022
1 parent e75bef5 commit e56cd51
Show file tree
Hide file tree
Showing 9 changed files with 509 additions and 733 deletions.
18 changes: 5 additions & 13 deletions pants-plugins/internal_plugins/releases/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,20 @@
from pants.engine.unions import UnionRule
from pants.option.alias import CliAlias
from pants.option.config import _ChainedConfig
from pants.option.option_types import DictOption
from pants.option.options_bootstrapper import OptionsBootstrapper
from pants.option.subsystem import Subsystem
from pants.util.frozendict import FrozenDict
from pants.version import PANTS_SEMVER, VERSION


class PantsReleases(Subsystem):
options_scope = "pants-releases"
help = "Options for Pants's release process."

@classmethod
def register_options(cls, register):
super().register_options(register)
register(
"--release-notes",
type=dict,
help="A dict from branch name to release notes rst-file location.",
)

@property
def _release_notes(self) -> FrozenDict[str, str]:
return FrozenDict(self.options.release_notes)
_release_notes = DictOption[str](
"--release-notes",
help="A dict from branch name to release notes rst-file location.",
)

@classmethod
def _branch_name(cls, version: Version) -> str:
Expand Down
276 changes: 123 additions & 153 deletions src/python/pants/backend/docker/subsystems/docker_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@
import os
import sys
from textwrap import dedent
from typing import cast
from typing import Any

from pants.backend.docker.registries import DockerRegistries
from pants.engine.environment import Environment
from pants.option.custom_types import shell_str, workspace_path
from pants.option.option_types import (
DictOption,
ShellStrListOption,
StrListOption,
StrOption,
WorkspacePathOption,
)
from pants.option.subsystem import Subsystem
from pants.util.docutil import bin_name
from pants.util.memo import memoized_method
Expand All @@ -22,189 +28,153 @@
"https://docs.docker.com/engine/reference/commandline/cli/#environment-variables"
),
}
registries_help = (
dedent(
"""\
Configure Docker registries. The schema for a registry entry is as follows:
{
"registry-alias": {
"address": "registry-domain:port",
"default": bool,
},
...
}
"""
)
+ (
"If no registries are provided in a `docker_image` target, then all default "
"addresses will be used, if any.\n"
"The `docker_image.registries` may be provided with a list of registry addresses "
"and registry aliases prefixed with `@` to be used instead of the defaults.\n"
"A configured registry is marked as default either by setting `default = true` "
'or with an alias of `"default"`.'
)
)
default_repository_help = (
"Configure the default repository name used in the Docker image tag.\n\n"
"The value is formatted and may reference these variables (in addition to the normal "
"placeheolders derived from the Dockerfile and build args etc):\n\n"
+ bullet_list(["name", "directory", "parent_directory"])
+ "\n\n"
'Example: `--default-repository="{directory}/{name}"`.\n\n'
"The `name` variable is the `docker_image`'s target name, `directory` and "
"`parent_directory` are the name of the directory in which the BUILD file is for the "
"target, and its parent directory respectively.\n\n"
"Use the `repository` field to set this value directly on a `docker_image` "
"target.\nAny registries or tags are added to the image name as required, and should "
"not be part of the repository name."
)


class DockerOptions(Subsystem):
options_scope = "docker"
help = "Options for interacting with Docker."

@classmethod
def register_options(cls, register):
registries_help = (
dedent(
"""\
Configure Docker registries. The schema for a registry entry is as follows:
{
"registry-alias": {
"address": "registry-domain:port",
"default": bool,
},
...
}
"""
)
+ (
"If no registries are provided in a `docker_image` target, then all default "
"addresses will be used, if any.\n"
"The `docker_image.registries` may be provided with a list of registry addresses "
"and registry aliases prefixed with `@` to be used instead of the defaults.\n"
"A configured registry is marked as default either by setting `default = true` "
'or with an alias of `"default"`.'
)
)
default_repository_help = (
"Configure the default repository name used in the Docker image tag.\n\n"
"The value is formatted and may reference these variables (in addition to the normal "
"placeheolders derived from the Dockerfile and build args etc):\n\n"
+ bullet_list(["name", "directory", "parent_directory"])
+ "\n\n"
'Example: `--default-repository="{directory}/{name}"`.\n\n'
"The `name` variable is the `docker_image`'s target name, `directory` and "
"`parent_directory` are the name of the directory in which the BUILD file is for the "
"target, and its parent directory respectively.\n\n"
"Use the `repository` field to set this value directly on a `docker_image` "
"target.\nAny registries or tags are added to the image name as required, and should "
"not be part of the repository name."
)
super().register_options(register)
register("--registries", type=dict, fromfile=True, help=registries_help)
register(
"--default-repository",
type=str,
help=default_repository_help,
default="{name}",
)

register(
"--default-context-root",
type=workspace_path,
default="",
help=(
"Provide a default Docker build context root path for `docker_image` targets that "
"does not specify their own `context_root` field.\n\n"
"The context root is relative to the build root by default, but may be prefixed "
"with `./` to be relative to the directory of the BUILD file of the `docker_image`."
"\n\nExamples:\n\n"
" --default-context-root=src/docker\n"
" --default-context-root=./relative_to_the_build_file\n"
),
)

register(
"--build-args",
type=list,
member_type=shell_str,
default=[],
help=(
"Global build arguments (for Docker `--build-arg` options) to use for all "
"`docker build` invocations.\n\n"
"Entries are either strings in the form `ARG_NAME=value` to set an explicit value; "
"or just `ARG_NAME` to copy the value from Pants's own environment.\n\n"
+ dedent(
f"""\
_registries = DictOption[Any]("--registries", help=registries_help).from_file()
default_repository = StrOption(
"--default-repository",
help=default_repository_help,
default="{name}",
)
default_context_root = WorkspacePathOption(
"--default-context-root",
default="",
help=(
"Provide a default Docker build context root path for `docker_image` targets that "
"does not specify their own `context_root` field.\n\n"
"The context root is relative to the build root by default, but may be prefixed "
"with `./` to be relative to the directory of the BUILD file of the `docker_image`."
"\n\nExamples:\n\n"
" --default-context-root=src/docker\n"
" --default-context-root=./relative_to_the_build_file\n"
),
)
_build_args = ShellStrListOption(
"--build-args",
help=(
"Global build arguments (for Docker `--build-arg` options) to use for all "
"`docker build` invocations.\n\n"
"Entries are either strings in the form `ARG_NAME=value` to set an explicit value; "
"or just `ARG_NAME` to copy the value from Pants's own environment.\n\n"
+ dedent(
f"""\
Example:
[{cls.options_scope}]
[{options_scope}]
build_args = ["VAR1=value", "VAR2"]
"""
)
+ "Use the `extra_build_args` field on a `docker_image` target for additional "
"image specific build arguments."
),
)

register(
"--build-target-stage",
type=str,
help=(
"Global default value for `target_stage` on `docker_image` targets, overriding "
"the field value on the targets, if there is a matching stage in the `Dockerfile`."
"\n\n"
"This is useful to provide from the command line, to specify the target stage to "
"build for at execution time."
),
)

register(
"--env-vars",
type=list,
member_type=shell_str,
default=[],
advanced=True,
help=(
"Environment variables to set for `docker` invocations.\n\n"
"Entries are either strings in the form `ENV_VAR=value` to set an explicit value; "
"or just `ENV_VAR` to copy the value from Pants's own environment."
),
)

register(
"--run-args",
type=list,
member_type=shell_str,
default=["--interactive", "--tty"] if sys.stdout.isatty() else [],
help=(
"Additional arguments to use for `docker run` invocations.\n\n"
"Example:\n\n"
f' $ {bin_name()} run --{cls.options_scope}-run-args="-p 127.0.0.1:80:8080/tcp '
'--name demo" src/example:image -- [image entrypoint args]\n\n'
"To provide the top-level options to the `docker` client, use "
f"`[{cls.options_scope}].env_vars` to configure the [Environment variables]("
f"{doc_links['docker_env_vars']}) as appropriate.\n\n"
"The arguments for the image entrypoint may be passed on the command line after a "
"double dash (`--`), or using the `--run-args` option.\n\n"
"Defaults to `--interactive --tty` when stdout is connected to a terminal."
),
)

register(
)
+ "Use the `extra_build_args` field on a `docker_image` target for additional "
"image specific build arguments."
),
)
build_target_stage = StrOption(
"--build-target-stage",
help=(
"Global default value for `target_stage` on `docker_image` targets, overriding "
"the field value on the targets, if there is a matching stage in the `Dockerfile`."
"\n\n"
"This is useful to provide from the command line, to specify the target stage to "
"build for at execution time."
),
)
_env_vars = ShellStrListOption(
"--env-vars",
help=(
"Environment variables to set for `docker` invocations.\n\n"
"Entries are either strings in the form `ENV_VAR=value` to set an explicit value; "
"or just `ENV_VAR` to copy the value from Pants's own environment."
),
).advanced()
run_args = ShellStrListOption(
"--run-args",
default=["--interactive", "--tty"] if sys.stdout.isatty() else [],
help=(
"Additional arguments to use for `docker run` invocations.\n\n"
"Example:\n\n"
f' $ {bin_name()} run --{options_scope}-run-args="-p 127.0.0.1:80:8080/tcp '
'--name demo" src/example:image -- [image entrypoint args]\n\n'
"To provide the top-level options to the `docker` client, use "
f"`[{options_scope}].env_vars` to configure the [Environment variables]("
f"{doc_links['docker_env_vars']}) as appropriate.\n\n"
"The arguments for the image entrypoint may be passed on the command line after a "
"double dash (`--`), or using the `--run-args` option.\n\n"
"Defaults to `--interactive --tty` when stdout is connected to a terminal."
),
)
_executable_search_paths = (
StrListOption(
"--executable-search-paths",
advanced=True,
type=list,
default=["<PATH>"],
metavar="<binary-paths>",
help=(
"The PATH value that will be used to find the Docker client and any tools required."
"\n\n"
'The special string `"<PATH>"` will expand to the contents of the PATH env var.'
),
)
.advanced()
.metavar("<binary-paths>")
)

@property
def build_args(self) -> tuple[str, ...]:
return tuple(sorted(set(self.options.build_args)))

@property
def build_target_stage(self) -> str | None:
return cast("str | None", self.options.build_target_stage)

@property
def run_args(self) -> tuple[str, ...]:
return tuple(self.options.run_args)
return tuple(sorted(set(self._build_args)))

@property
def env_vars(self) -> tuple[str, ...]:
return tuple(sorted(set(self.options.env_vars)))

@property
def default_context_root(self) -> str:
return cast(str, self.options.default_context_root)

@property
def default_repository(self) -> str:
return cast(str, self.options.default_repository)
return tuple(sorted(set(self._env_vars)))

@memoized_method
def registries(self) -> DockerRegistries:
return DockerRegistries.from_dict(self.options.registries)
return DockerRegistries.from_dict(self._registries)

@memoized_method
def executable_search_path(self, env: Environment) -> tuple[str, ...]:
def iter_path_entries():
for entry in self.options.executable_search_paths:
for entry in self._executable_search_paths:
if entry == "<PATH>":
path = env.get("PATH")
if path:
Expand Down
Loading

0 comments on commit e56cd51

Please sign in to comment.