code: def main(
      py_versions: Tuple[str],
      device_types: Tuple[str],
      build_type: str,
      suffix: Optional[str] = None,
      build_base: bool = True,
      only_build_worker_container: bool = False,
  ):
      py_versions = (
          list(py_versions)
          if isinstance(py_versions, (list, tuple))
          else [py_versions]
      )
      image_types = (
          list(device_types)
          if isinstance(device_types, (list, tuple))
          else list(BASE_IMAGES.keys())
      )
  
      assert set(list(CUDA_FULL.keys()) + ["cpu"]) == set(
          BASE_IMAGES.keys()
      )
  
      # Make sure the python images and cuda versions we build here are
      # consistent with the ones used with fix-latest-docker.sh script.
      py_version_file = os.path.join(
          _get_root_dir(), "docker/retag-lambda", "python_versions.txt"
      )
      with open(py_version_file) as f:
          py_file_versions = f.read().splitlines()
          assert set(PY_MATRIX.keys()) == set(py_file_versions), (
              PY_MATRIX.keys(),
              py_file_versions,
          )
  
      cuda_version_file = os.path.join(
          _get_root_dir(), "docker/retag-lambda", "cuda_versions.txt"
      )
  
      with open(cuda_version_file) as f:
          cuda_file_versions = f.read().splitlines()
          assert set(BASE_IMAGES.keys()) == set(
              cuda_file_versions + ["cpu"]
          ), (
              BASE_IMAGES.keys(),
              cuda_file_versions + ["cpu"],
          )
  
      print(
          "Building the following python versions: ",
          [PY_MATRIX[py_version] for py_version in py_versions],
      )
      print("Building images for the following devices: ", image_types)
      print("Building base images: ", build_base)
  
      is_buildkite = build_type == BUILDKITE
      is_local = build_type == LOCAL
  
      if build_type == BUILDKITE:
          if os.environ.get("BUILDKITE_PULL_REQUEST", "") == "false":
              build_type = MERGE
          elif (
              os.environ.get("BUILDKITE_PIPELINE_ID", "")
              == RELEASE_PR_PIPELINE_ID
          ):
              build_type = RELEASE_PR
          else:
              build_type = PR
  
      if build_type == HUMAN:
          # If manually triggered, request user for branch and SHA value to use.
          _configure_human_version()
      if (
          build_type in {HUMAN, MERGE, BUILDKITE, LOCAL, RELEASE_PR}
          or _check_if_docker_files_modified()
          or only_build_worker_container
      ):
          is_merge = build_type == MERGE
          # Buildkite is authenticated in the background.
          if is_merge and not is_buildkite and not is_local:
              # We do this here because we want to be authenticated for
              # Docker pulls as well as pushes (to avoid rate-limits).
              username, password = _get_docker_creds()
              DOCKER_CLIENT.api.login(
                  username=username, password=password
              )
          copy_wheels(build_type == HUMAN)
          is_base_images_built = build_or_pull_base_images(
              py_versions, image_types, build_base, suffix=suffix
          )
  
          if only_build_worker_container:
              build_for_all_versions(
                  "ray-worker-container",
                  py_versions,
                  image_types,
                  suffix=suffix,
              )
              # TODO Currently don't push ray_worker_container
          else:
              # Build Ray Docker images.
              prep_ray_base()
  
              all_tagged_images = []
  
              all_tagged_images += build_for_all_versions(
                  "ray", py_versions, image_types, suffix=suffix
              )
  
              # List of images to tag and push to docker hub
              images_to_tag_and_push = []
  
              if is_base_images_built:
                  images_to_tag_and_push += ["base-deps", "ray-deps"]
  
              # Always tag/push ray
              images_to_tag_and_push += ["ray"]
  
              # Only build ML Docker images for ML_CUDA_VERSION or cpu.
              if platform.processor() not in ADDITIONAL_PLATFORMS:
                  ml_image_types = [
                      image_type
                      for image_type in image_types
                      if image_type in [ML_CUDA_VERSION, "cpu"]
                  ]
              else:
                  # Do not build ray-ml e.g. for arm64
                  ml_image_types = []
  
              # Only build ray-ml image for pythons in ML_IMAGES_PY_VERSIONS
              ml_py_versions = [
                  py_version
                  for py_version in py_versions
                  if py_version in ML_IMAGES_PY_VERSIONS
              ]
  
              if len(ml_image_types) > 0:
                  prep_ray_ml()
                  all_tagged_images += build_for_all_versions(
                      "ray-ml",
                      ml_py_versions,
                      image_types=ml_image_types,
                      suffix=suffix,
                  )
                  images_to_tag_and_push += ["ray-ml"]
  
              if is_buildkite:
                  extract_image_infos(
                      all_tagged_images,
                      target_dir="/artifact-mount/.image-info",
                  )
  
              if build_type in {MERGE, RELEASE_PR}:
                  valid_branch = _valid_branch()
                  if (not valid_branch) and is_merge:
                      print(f"Invalid Branch found: {_get_branch()}")
                  push_and_tag_images(
                      py_versions,
                      image_types,
                      merge_build=valid_branch and is_merge,
                      release_pr_build=build_type == RELEASE_PR,
                      image_list=images_to_tag_and_push,
                      suffix=suffix,
                  )
  
imports: import datetime
  import io
  import json
  import functools
  import glob
  import itertools
  import os
  import platform
  import shutil
  import subprocess
  import sys
  import tarfile
  from collections import defaultdict
  from pathlib import Path
  from typing import List, Optional, Tuple, Dict
  import click
  import docker
label_desc: Use image node_id 28 for calling a global function with example usage: main(py_versions, device_types, build_type, suffix, build_base, only_build_worker_container) without return types