7
0
mirror of https://github.com/ChristianLight/tutor.git synced 2024-06-27 09:03:28 +00:00

feat: auto-complete image names in images build/pull/...

This commit is contained in:
Régis Behmo 2023-05-04 11:39:02 +02:00
parent 947b37524f
commit 5ce39d36e2
2 changed files with 57 additions and 6 deletions

View File

@ -13,3 +13,4 @@
- The "openedx" Docker image in development can be built with `tutor images build openedx-dev`. - The "openedx" Docker image in development can be built with `tutor images build openedx-dev`.
- The `tutor dev/local start --skip-build` option is removed. It is replaced by opt-in `--build`. - The `tutor dev/local start --skip-build` option is removed. It is replaced by opt-in `--build`.
- [Improvement] The `IMAGES_BUILD` filter now supports relative paths as strings, and not just as tuple of strings. - [Improvement] The `IMAGES_BUILD` filter now supports relative paths as strings, and not just as tuple of strings.
- [Improvement] Auto-complete the image names in the `images build/pull/push/printtag` commands.

View File

@ -7,7 +7,7 @@ import click
from tutor import config as tutor_config from tutor import config as tutor_config
from tutor import env as tutor_env from tutor import env as tutor_env
from tutor import exceptions, hooks, images, types, utils from tutor import exceptions, fmt, hooks, images, types, utils
from tutor.commands.context import Context from tutor.commands.context import Context
from tutor.core.hooks import Filter from tutor.core.hooks import Filter
from tutor.types import Config from tutor.types import Config
@ -87,13 +87,60 @@ def _add_core_images_to_push(
return remote_images return remote_images
class ImageNameParam(click.ParamType):
"""
Convenient auto-completion of image names.
"""
def shell_complete(
self, ctx: click.Context, param: click.Parameter, incomplete: str
) -> list[click.shell_completion.CompletionItem]:
# Hackish way to get the project root and config
root = getattr(
getattr(getattr(ctx, "parent", None), "parent", None), "params", {}
).get("root", "")
config = tutor_config.load_full(root)
results = []
for name in self.iter_image_names(config):
if name.startswith(incomplete):
results.append(click.shell_completion.CompletionItem(name))
return results
def iter_image_names(self, config: Config) -> t.Iterable["str"]:
raise NotImplementedError
class BuildImageNameParam(ImageNameParam):
def iter_image_names(self, config: Config) -> t.Iterable["str"]:
for name, _path, _tag, _args in hooks.Filters.IMAGES_BUILD.iterate(config):
yield name
class PullImageNameParam(ImageNameParam):
def iter_image_names(self, config: Config) -> t.Iterable["str"]:
for name, _tag in hooks.Filters.IMAGES_PULL.iterate(config):
yield name
class PushImageNameParam(ImageNameParam):
def iter_image_names(self, config: Config) -> t.Iterable["str"]:
for name, _tag in hooks.Filters.IMAGES_PUSH.iterate(config):
yield name
@click.group(name="images", short_help="Manage docker images") @click.group(name="images", short_help="Manage docker images")
def images_command() -> None: def images_command() -> None:
pass pass
@click.command() @click.command()
@click.argument("image_names", metavar="image", nargs=-1) @click.argument(
"image_names",
metavar="image",
nargs=-1,
type=BuildImageNameParam(),
)
@click.option( @click.option(
"--no-cache", is_flag=True, help="Do not use cache when building the image" "--no-cache", is_flag=True, help="Do not use cache when building the image"
) )
@ -207,7 +254,7 @@ def get_image_build_contexts(config: Config) -> dict[str, list[tuple[str, str]]]
instance to build a Docker image with a local git checkout of a remote repo. instance to build a Docker image with a local git checkout of a remote repo.
Users configure bind-mounts with the `MOUNTS` config setting. Plugins can then Users configure bind-mounts with the `MOUNTS` config setting. Plugins can then
automaticall add build contexts based on these values. automatically add build contexts based on these values.
""" """
user_mounts = types.get_typed(config, "MOUNTS", list) user_mounts = types.get_typed(config, "MOUNTS", list)
build_contexts: dict[str, list[tuple[str, str]]] = {} build_contexts: dict[str, list[tuple[str, str]]] = {}
@ -215,6 +262,9 @@ def get_image_build_contexts(config: Config) -> dict[str, list[tuple[str, str]]]
for image_name, stage_name in hooks.Filters.IMAGES_BUILD_MOUNTS.iterate( for image_name, stage_name in hooks.Filters.IMAGES_BUILD_MOUNTS.iterate(
user_mount user_mount
): ):
fmt.echo_info(
f"Adding {user_mount} to the build context '{stage_name}' of image '{image_name}'"
)
if image_name not in build_contexts: if image_name not in build_contexts:
build_contexts[image_name] = [] build_contexts[image_name] = []
build_contexts[image_name].append((user_mount, stage_name)) build_contexts[image_name].append((user_mount, stage_name))
@ -236,7 +286,7 @@ def _mount_edx_platform(
@click.command(short_help="Pull images from the Docker registry") @click.command(short_help="Pull images from the Docker registry")
@click.argument("image_names", metavar="image", nargs=-1) @click.argument("image_names", metavar="image", type=PullImageNameParam(), nargs=-1)
@click.pass_obj @click.pass_obj
def pull(context: Context, image_names: list[str]) -> None: def pull(context: Context, image_names: list[str]) -> None:
config = tutor_config.load_full(context.root) config = tutor_config.load_full(context.root)
@ -246,7 +296,7 @@ def pull(context: Context, image_names: list[str]) -> None:
@click.command(short_help="Push images to the Docker registry") @click.command(short_help="Push images to the Docker registry")
@click.argument("image_names", metavar="image", nargs=-1) @click.argument("image_names", metavar="image", type=PushImageNameParam(), nargs=-1)
@click.pass_obj @click.pass_obj
def push(context: Context, image_names: list[str]) -> None: def push(context: Context, image_names: list[str]) -> None:
config = tutor_config.load_full(context.root) config = tutor_config.load_full(context.root)
@ -256,7 +306,7 @@ def push(context: Context, image_names: list[str]) -> None:
@click.command(short_help="Print tag associated to a Docker image") @click.command(short_help="Print tag associated to a Docker image")
@click.argument("image_names", metavar="image", nargs=-1) @click.argument("image_names", metavar="image", type=BuildImageNameParam(), nargs=-1)
@click.pass_obj @click.pass_obj
def printtag(context: Context, image_names: list[str]) -> None: def printtag(context: Context, image_names: list[str]) -> None:
config = tutor_config.load_full(context.root) config = tutor_config.load_full(context.root)