text: #!/usr/bin/env python
  from __future__ import print_function
  
  import sys
  from shutil import copy, rmtree
  import distutils.dir_util as dir_util
  from subprocess import call
  from tempfile import mkdtemp
  
  from atexit import register
  from os import getenv, mkdir, remove
  from os.path import abspath, dirname, isdir, join
  
  if len(sys.argv) > 1 and sys.argv[1] in ['-h', '--h', '-help', '--help']:
      print("""Quickly re-build images depending on OpenShift Origin build artifacts.
  
  This script re-builds OpenShift Origin images quickly. It is intended
  to be used by developers for quick, iterative development of images
  that depend on binaries, RPMs, or other artifacts that the Origin build
  process generates. The script works by creating a temporary context
  directory for a Docker build, adding a simple Dockerfile FROM the image
  you wish to rebuild, ADDing in static files to overwrite, and building.
  
  The script supports ADDing binaries from origin/_output/local/bin/linux/amd64/
  and ADDing static files from the original context directories under the
  origin/images/ directories.
  
  Usage:
    [OS_DEBUG=true] [OS_IMAGE_PREFIX=prefix] [OS_USE_BUILDAH=true] build-local-images.py [IMAGE...]
  
    Specific images can be specified to be built with either the full name
    of the image (e.g. openshift3/ose-haproxy-router) or the name sans prefix
    (e.g. haproxy-router).
  
    The following environment variables are honored by this script:
     - $OS_IMAGE_PREFIX: one of [openshift/origin, docker.io/openshift/origin, openshift3/ose]
     - $OS_DEBUG: if set, debugging information will be printed
     - $OS_USE_BUILDAH: if set, use buildah to build the images instead of Docker
  
  Examples:
    # build all images
    build-local-images.py
  
    # build only the f5-router image
    build-local-images.py f5-router
  
    # build with a different image prefix
    OS_IMAGE_PREFIX=openshift3/ose build-local-images.sh
  
    # build with a different tag
    OS_IMAGE_TAG=v3.x.y build-local-images.sh
  
  Options:
    -h,--h, -help,--help: show this help-text
  """)
      exit(2)
  
  os_image_prefix = getenv("OS_IMAGE_PREFIX", "openshift/origin")
  os_image_tag = getenv("OS_IMAGE_TAG", "latest")
  os_use_buildah = getenv("OS_USE_BUILDAH")
  image_namespace, _, image_prefix = os_image_prefix.rpartition("/")
  
  # "enable_default: True" can be added to skip the image build
  # with no arguments
  image_config = {
      "hyperkube": {
          "tag": "latest",
          "directory": "hyperkube",
          "binaries": {
              "kube-apiserver": "/usr/bin/kube-apiserver",
              "kube-controller-manager": "/usr/bin/kube-controller-manager",
              "kube-scheduler": "/usr/bin/kube-scheduler",
              "kubelet": "/usr/bin/kubelet",
          },
          "files": {"hyperkube" : "/usr/bin/hyperkube"}
      }
  }
  
  
  def image_rebuild_requested(image):
      """
      An image rebuild is requested if the
      user provides the image name or image
      suffix explicitly or does not provide
      any explicit requests.
      """
      implicitly_triggered = len(sys.argv) == 1 and image_config[image].get("enable_default", True)
      explicitly_triggered = len(sys.argv) > 1 and (image in sys.argv or full_name(image) in sys.argv)
      return implicitly_triggered or explicitly_triggered
  
  
  def full_name(image):
      """
      The full name of the image will contain
      the image namespace as well as the pre-
      fix, if applicable.
      """
      return "{}/{}-{}".format(image_namespace, image_prefix, image)
  
  
  def add_to_context(context_dir, source, destination, container_destination):
      """
      Add a file to the context directory
      and add an entry to the Dockerfile
      to place it in the container file-
      sytem at the correct destination.
      """
      debug("Adding file:\n\tfrom {}\n\tto {}\n\tincluding in container at {}".format(
          source,
          join(context_dir, destination),
          container_destination)
      )
      absolute_destination = abspath(join(context_dir, destination))
      if isdir(source):
          dir_util.copy_tree(source, absolute_destination)
      else:
          copy(source, absolute_destination)
      with open(join(context_dir, "Dockerfile"), "a") as dockerfile:
          dockerfile.write("ADD {} {}\n".format(destination, container_destination))
  
  
  def debug(message):
      if getenv("OS_DEBUG"):
          print("[DEBUG] {}".format(message))
  
  
  os_root = abspath(join(dirname(__file__), ".."))
  os_image_path = join(os_root, "images")
  
  context_dir = mkdtemp()
  register(rmtree, context_dir)
  
  debug("Created temporary context dir at {}".format(context_dir))
  mkdir(join(context_dir, "bin"))
  mkdir(join(context_dir, "src"))
  
  build_occurred = False
  for image in image_config:
      if not image_rebuild_requested(image):
          continue
  
      build_occurred = True
      print("[INFO] Building {}...".format(image))
      with open(join(context_dir, "Dockerfile"), "w+") as dockerfile:
          dockerfile.write("FROM {}:{}\n".format(full_name(image), image_config[image]["tag"]))
  
  
      binary_dir_args = ["_output", "local", "bin", "linux", "amd64"]
      config = image_config[image]
      for binary in config.get("binaries", []):
          if "vendor_dir" in config:
              os_bin_path = join(os_root, config.get("vendor_dir"), *binary_dir_args)
          else:
              os_bin_path = join(os_root, *binary_dir_args)
  
          add_to_context(
              context_dir,
              source=join(os_bin_path, binary),
              destination=join("bin", binary),
              container_destination=config["binaries"][binary]
          )
  
      mkdir(join(context_dir, "src", image))
      for file in config.get("files", []):
          add_to_context(
              context_dir,
              source=join(os_image_path, config["directory"], file),
              destination=join("src", image, file),
              container_destination=config["files"][file]
          )
      
      if os_use_buildah:
          debug("Initiating buildah build with Dockerfile:\n{}".format(open(join(context_dir, "Dockerfile")).read()))
          # re-pull the original image before building it so we're not accumulating layers each time we
          # rebuild the image.
          call(["buildah", "pull", full_name(image) + ":" + image_config[image]["tag"]])
          call(["buildah", "bud", "-t", full_name(image) + ":" + os_image_tag, "."], cwd=context_dir)
      else:
          debug("Initiating Docker build with Dockerfile:\n{}".format(open(join(context_dir, "Dockerfile")).read()))
          # re-pull the original image before building it so we're not accumulating layers each time we
          # rebuild the image.
          call(["docker", "pull", full_name(image) + ":" + image_config[image]["tag"]])
          call(["docker", "build", "-t", full_name(image) + ":" + os_image_tag, "."], cwd=context_dir)
  
      remove(join(context_dir, "Dockerfile"))
      rmtree(join(context_dir, "src", image))
  
  if not build_occurred and len(sys.argv) > 1:
      print(
          "[ERROR] The provided image names ({}) did not match any buildable images."
          .format(", ".join(sys.argv[1:]))
      )
      print(
          "[ERROR] This script knows how to build:\n\t{}"
          .format("\n\t".join(map(full_name, image_config.keys())))
      )
      exit(1)
  