# -*- coding: utf-8 -*-
          from __future__ import absolute_import
          from __future__ import unicode_literals
          
          import logging
          import os
          import sys
          import warnings
          from collections import defaultdict
          from distutils.version import LooseVersion
          
          import six
          
          from docker.errors import DockerException
          from docker.utils import (
              compare_version,
              convert_bool,
              parse_bytes,
              parse_host,
              parse_repository_tag,
              convert_port_string,
              parse_env_file,
              normalize_name,
              convert_service_names,
              convert_service_ports,
          )
          
          log = logging.getLogger(__name__)
          
          try:
              from ConfigParser import SafeConfigParser
          except ImportError:
              from configparser import SafeConfigParser
          
          # This class is a container for various configuration settings.
          class DockerClientConfig(object):
              """
              This class is a container for various configuration settings.
          
              :param config_file: Path to the configuration file to use.
              :type config_file: str
              :param version: Version of the Docker API to use. If not specified, the
                  client will attempt to auto-detect the server API version.
              :type version: str
              :param timeout: Default timeout for HTTP requests in seconds.
              :type timeout: int
              :param max_pool_size: Maximum number of connections to keep in the pool.
              :type max_pool_size: int
              :param base_url: Base URL of the Docker daemon.
              :type base_url: str
              :param tls: Use TLS to connect to the Docker daemon.
              :type tls: bool
              :param tlsverify: Verify TLS connections.
              :type tlsverify: bool
              :param cert_path: Path to TLS certificate.
              :type cert_path: str
              :param client_cert: Path to TLS client certificate.
              :type client_cert: str
              :param client_key: Path to TLS client key.
              :type client_key: str
              :param ca_cert: Path to the certificate authority certificate.
              :type ca_cert: str
              :param assert_hostname: Verify hostname of Docker daemon.
              :type assert_hostname: bool
              :param registry: Default registry to use when building images.
              :type registry: str
              :param insecure_registry: A list of insecure registries.
              :type insecure_registry: list
              :param email: Default email to use when pushing images.
              :type email: str
              :param username: Default username to use when pushing images.
              :type username: str
              :param password: Default password to use when pushing images.
              :type password: str
              :param auth_config: Dictionary containing the auth config for different
                  registries.
              :type auth_config: dict
              :param environment: A list of environment variables to set.
              :type environment: list
              :param http_proxy: Proxy to use for HTTP requests.
              :type http_proxy: str
              :param https_proxy: Proxy to use for HTTPS requests.
              :type https_proxy: str
              :param no_proxy: A list of hosts that should not be proxied.
              :type no_proxy: list
              :param stream: Default for stream argument.
              :type stream: bool
              :param raise_for_status: Raise for API response errors.
              :type raise_for_status: bool
              :param api_version: Use a specific API version.
              :type api_version: str
              :param version: Version of the Docker API to use. If not specified, the
                  client will attempt to auto-detect the server API version.
              :type version: str
              :param user_agent: Set a custom user agent.
              :type user_agent: str
              :param universal_fe_compatible: Whether to use a universal feed endpoint
              :type universal_fe_compatible: bool
              :param log_level: Set the log level for the client.
              :type log_level: int
              :param log_config: Set the log configuration for the client.
              :type log_config: dict
              :param machine_name: The name of the machine.
              :type machine_name: str
              :param machine_storage_path: The path to the machine storage.
              :type machine_storage_path: str
              :param tls_hostname: The TLS hostname to use for the Docker daemon.
              :type tls_hostname: str
              :param platform: Platform to use for building images.
              :type platform: str
              :param experimental: Enable experimental features.
              :type experimental: bool
              :param image_load_parallelism: The maximum number of image layers that
                  will be loaded in parallel.
              :type image_load_parallelism: int
              :param network_mode: Default network mode for containers.
              :type network_mode: str
              :param default_command_shell: Default command shell for containers.
              :type default_command_shell: str
              :param default_log_driver: Default log driver for containers.
              :type default_log_driver: str
              :param system_context: Dictionary containing system context values.
              :type system_context: dict
              :param network_alias:  A map of network aliases for containers.
              :type network_alias: dict
              :param default_backend:  The default backend to use for operations.
              :type default_backend: str
              :param client_timeout:  Client timeout in seconds.
              :type client_timeout: int
              :param max_concurrent_builds:  The maximum number of builds to run concurrently.
              :type max_concurrent_builds: int
              :param max_concurrent_dind_builds:  The maximum number of builds to run concurrently for dind builds.
              :type max_concurrent_dind_builds: int
              :param version_check:  Check the Docker API version of the server on startup.
              :type version_check: bool
              :param build_cache_max_size:  The maximum size of the build cache in bytes.
              :type build_cache_max_size: int
          
              :raises: :py:exc:`~docker.errors.DockerException`
              """
          
              def __init__(
                  self,
                  config_file=None,
                  version=None,
                  timeout=None,
                  max_pool_size=None,
                  base_url=None,
                  tls=None,
                  tlsverify=None,
                  cert_path=None,
                  client_cert=None,
                  client_key=None,
                  ca_cert=None,
                  assert_hostname=None,
                  registry=None,
                  insecure_registry=None,
                  email=None,
                  username=None,
                  password=None,
                  auth_config=None,
                  environment=None,
                  http_proxy=None,
                  https_proxy=None,
                  no_proxy=None,
                  stream=None,
                  raise_for_status=None,
                  api_version=None,
                  user_agent=None,
                  universal_fe_compatible=None,
                  log_level=None,
                  log_config=None,
                  machine_name=None,
                  machine_storage_path=None,
                  tls_hostname=None,
                  platform=None,
                  experimental=None,
                  image_load_parallelism=None,
                  network_mode=None,
                  default_command_shell=None,
                  default_log_driver=None,
                  system_context=None,
                  network_alias=None,
                  default_backend=None,
                  client_timeout=None,
                  max_concurrent_builds=None,
                  max_concurrent_dind_builds=None,
                  version_check=None,
                  build_cache_max_size=None,
              ):
                  self.config_file = config_file
                  self._base_url = base_url
                  self._tls = tls
                  self._tlsverify = tlsverify
                  self._cert_path = cert_path
                  self._client_cert = client_cert
                  self._client_key = client_key
                  self._ca_cert = ca_cert
                  self._assert_hostname = assert_hostname
                  self._registry = registry
                  self._insecure_registry = insecure_registry
                  self._email = email
                  self._username = username
                  self._password = password
                  self.auth_config = auth_config or {}
                  self._environment = environment
                  self._http_proxy = http_proxy
                  self._https_proxy = https_proxy
                  self._no_proxy = no_proxy
                  self._stream = stream
                  self._raise_for_status = raise_for_status
                  self._api_version = api_version
                  self.user_agent = user_agent
                  self._universal_fe_compatible = universal_fe_compatible
                  self._log_level = log_level
                  self._log_config = log_config
                  self._machine_name = machine_name
                  self._machine_storage_path = machine_storage_path
                  self._tls_hostname = tls_hostname
                  self._platform = platform
                  self._experimental = experimental
                  self._image_load_parallelism = image_load_parallelism
                  self._network_mode = network_mode
                  self._default_command_shell = default_command_shell
                  self._default_log_driver = default_log_driver
                  self._system_context = system_context or {}
                  self._network_alias = network_alias
                  self._default_backend = default_backend
                  self._client_timeout = client_timeout
                  self._max_concurrent_builds = max_concurrent_builds
                  self._max_concurrent_dind_builds = max_concurrent_dind_builds
                  self._version_check = version_check
                  self._build_cache_max_size = build_cache_max_size
                  if timeout is not None:
                      warnings.warn(
                          "The `timeout` parameter is deprecated and will be removed "
                          "in a future release.  Use `client_timeout` instead.",
                          DeprecationWarning,
                      )
                      self.client_timeout = timeout
                  if max_pool_size is not None:
                      warnings.warn(
                          "The `max_pool_size` parameter is deprecated and will be "
                          "removed in a future release.",
                          DeprecationWarning,
                      )
                  if version is not None:
                      warnings.warn(
                          "The `version` parameter is deprecated and will be removed "
                          "in a future release.  Use `api_version` instead.",
                          DeprecationWarning,
                      )
                      self.api_version = version
          
                  self._load_config(config_file)
          
              def _get_env_config(self, config_file):
                  """Return a dictionary with environment variables to be injected
                  from a docker environment file.
                  """
                  if not config_file:
                      return None
                  env_file = os.path.join(os.path.dirname(config_file), ".dockerenv")
                  if os.path.isfile(env_file):
                      return parse_env_file(env_file)
                  return None
          
              def _load_config(self, config_file):
                  """Loads the configuration from the provided file.
          
                  :param config_file: Path to the configuration file to use.
                  :type config_file: str
                  """
                  env_config = self._get_env_config(config_file)
          
                  if not config_file:
                      return
          
                  # Load config from .dockercfg
                  self.config = SafeConfigParser()
                  try:
                      self.config.read(config_file)
                  except Exception as e:
                      # If there is an error, the client can still be used,
                      # although it will not be able to authenticate with Docker
                      # Hub. This is not a critical issue for most users, so we
                      # just log a warning.
                      log.warning("Could not load config file: %s" % e)
          
                  # Set values from config file
                  if self.config.has_section("DEFAULT"):
                      # Environment
                      self._environment = (
                          self.config.get("DEFAULT", "environment").split(":")
                          if self.config.has_option("DEFAULT", "environment")
                          else None
                      )
          
                      # HTTP Proxy
                      self._http_proxy = (
                          self.config.get("DEFAULT", "http_proxy")
                          if self.config.has_option("DEFAULT", "http_proxy")
                          else None
                      )
          
                      # HTTPS Proxy
                      self._https_proxy = (
                          self.config.get("DEFAULT", "https_proxy")
                          if self.config.has_option("DEFAULT", "https_proxy")
                          else None
                      )
          
                      # No Proxy
                      self._no_proxy = (
                          self.config.get("DEFAULT", "no_proxy").split(",")
                          if self.config.has_option("DEFAULT", "no_proxy")
                          else None
                      )
          
                      # Registry
                      self._registry = (
                          self.config.get("DEFAULT", "registry")
                          if self.config.has_option("DEFAULT", "registry")
                          else None
                      )
          
                      # Insecure registry
                      self._insecure_registry = (
                          self.config.get("DEFAULT", "insecure-registry").split(",")
                          if self.config.has_option("DEFAULT", "insecure-registry")
                          else None
                      )
          
                      # Auth config
                      if self.config.has_option("DEFAULT", "auths"):
                          auths = self.config.get("DEFAULT", "auths")
                          try:
                              self.auth_config = eval(auths)
                          except Exception as e:
                              log.warning(
                                  "Error parsing auths config in %s: %s" % (config_file, e)
                              )
                          if isinstance(self.auth_config, dict):
                              self.auth_config = defaultdict(dict, self.auth_config)
          
                      # Use environment vars if available
                      if env_config:
                          for k, v in env_config.items():
                              if isinstance(v, six.string_types):
                                  # Some environment variables may be in a format like
                                  #   "https://user:pass@host:port"
                                  # Docker uses URL quoting to allow the use of
                                  # special characters, so we need to unquote them
                                  # before using the environment variable as password
                                  # or username
                                  if "://" in v:
                                      (
                                          protocol,
                                          host_auth,
                                      ) = v.split("://", 1)
                                      if "@" in host_auth:
                                          (
                                              user_pass,
                                              host_port,
                                          ) = host_auth.split("@", 1)
                                          (
                                              username,
                                              password,
                                          ) = user_pass.split(":", 1)
                                          self.auth_config[host_port]["username"] = (
                                              username
                                          )
                                          self.auth_config[host_port]["password"] = (
                                              password
                                          )
          
                              self.auth_config[k]["username"] = (
                                  env_config.get(k, {}).get("username", None)
                              )
                              self.auth_config[k]["password"] = (
                                  env_config.get(k, {}).get("password", None)
                              )
                              self.auth_config[k]["email"] = (
                                  env_config.get(k, {}).get("email", None)
                              )
                              self.auth_config[k]["auth"] = (
                                  env_config.get(k, {}).get("auth", None)
                              )
          
                      for section in self.config.sections():
                          if not section == "DEFAULT":
                              auth_config = self.auth_config[section] = {}
                              if self.config.has_option(section, "username"):
                                  auth_config["username"] = self.config.get(
                                      section, "username"
                                  )
                              if self.config.has_option(section, "password"):
                                  auth_config["password"] = self.config.get(
                                      section, "password"
                                  )
                              if self.config.has_option(section, "email"):
                                  auth_config["email"] = self.config.get(
                                      section, "email"
                                  )
                              if self.config.has_option(section, "auth"):
                                  auth_config["auth"] = self.config.get(
                                      section, "auth"
                                  )
          
              def _get_base_url(self):
                  """Retrieve the base URL of the Docker daemon.
                  This method considers the environment variables and
                  configuration file.
                  """
                  if self._base_url:
                      return self._base_url
          
                  # Environment Variables
                  if "DOCKER_HOST" in os.environ:
                      host = parse_host(os.environ["DOCKER_HOST"])
                      base_url = "http" + ("://" + host if host else "")
                      return base_url
                  # Configuration File
                  if self.config.has_section("DEFAULT"):
                      if self.config.has_option("DEFAULT", "url"):
                          base_url = self.config.get("DEFAULT", "url")