text: # coding=utf-8
  import os
  import platform
  import sys
  
  from dbt.logger import GLOBAL_LOGGER as logger
  import dbt.clients.system
  import dbt.config
  import dbt.utils
  import dbt.exceptions
  from dbt.links import ProfileConfigDocs
  from dbt.adapters.factory import get_adapter, register_adapter
  from dbt.version import get_installed_version
  from dbt.config import Project, Profile
  from dbt.clients.yaml_helper import load_yaml_text
  from dbt.ui.printer import green, red
  
  from dbt.task.base import BaseTask
  
  PROFILE_DIR_MESSAGE = """To view your profiles.yml file, run:
  
  {open_cmd} {profiles_dir}"""
  
  ONLY_PROFILE_MESSAGE = '''
  A `dbt_project.yml` file was not found in this directory.
  Using the only profile `{}`.
  '''.lstrip()
  
  MULTIPLE_PROFILE_MESSAGE = '''
  A `dbt_project.yml` file was not found in this directory.
  dbt found the following profiles:
  {}
  
  To debug one of these profiles, run:
  dbt debug --profile [profile-name]
  '''.lstrip()
  
  COULD_NOT_CONNECT_MESSAGE = '''
  dbt was unable to connect to the specified database.
  The database returned the following error:
  
    >{err}
  
  Check your database credentials and try again. For more information, visit:
  {url}
  '''.lstrip()
  
  
  MISSING_PROFILE_MESSAGE = '''
  dbt looked for a profiles.yml file in {path}, but did
  not find one. For more information on configuring your profile, consult the
  documentation:
  
  {url}
  '''.lstrip()
  
  FILE_NOT_FOUND = 'file not found'
  
  
  class DebugTask(BaseTask):
      def __init__(self, args, config):
          super().__init__(args, config)
          self.profiles_dir = getattr(self.args, 'profiles_dir',
                                      dbt.config.PROFILES_DIR)
          self.profile_path = os.path.join(self.profiles_dir, 'profiles.yml')
          self.project_path = os.path.join(os.getcwd(), 'dbt_project.yml')
          self.cli_vars = dbt.utils.parse_cli_vars(
              getattr(self.args, 'vars', '{}')
          )
  
          # set by _load_*
          self.profile = None
          self.profile_fail_details = ''
          self.raw_profile_data = None
          self.profile_name = None
          self.project = None
          self.project_fail_details = ''
          self.messages = []
  
      @property
      def project_profile(self):
          if self.project is None:
              return None
          return self.project.profile_name
  
      def path_info(self):
          open_cmd = dbt.clients.system.open_dir_cmd()
  
          message = PROFILE_DIR_MESSAGE.format(
              open_cmd=open_cmd,
              profiles_dir=self.profiles_dir
          )
  
          logger.info(message)
  
      def run(self):
          if self.args.config_dir:
              self.path_info()
              return
  
          version = get_installed_version().to_version_string(skip_matcher=True)
          print('dbt version: {}'.format(version))
          print('python version: {}'.format(sys.version.split()[0]))
          print('python path: {}'.format(sys.executable))
          print('os info: {}'.format(platform.platform()))
          print('Using profiles.yml file at {}'.format(self.profile_path))
          print('')
          self.test_configuration()
          self.test_dependencies()
          self.test_connection()
  
          for message in self.messages:
              print(message)
              print('')
  
      def _load_project(self):
          if not os.path.exists(self.project_path):
              self.project_fail_details = FILE_NOT_FOUND
              return red('ERROR not found')
  
          try:
              self.project = Project.from_current_directory(self.cli_vars)
          except dbt.exceptions.DbtConfigError as exc:
              self.project_fail_details = str(exc)
              return red('ERROR invalid')
  
          return green('OK found and valid')
  
      def _profile_found(self):
          if not self.raw_profile_data:
              return red('ERROR not found')
          if self.profile_name in self.raw_profile_data:
              return green('OK found')
          else:
              return red('ERROR not found')
  
      def _target_found(self):
          requirements = (self.raw_profile_data and self.profile_name and
                          self.target_name)
          if not requirements:
              return red('ERROR not found')
          if self.profile_name not in self.raw_profile_data:
              return red('ERROR not found')
          profiles = self.raw_profile_data[self.profile_name]['outputs']
          if self.target_name not in profiles:
              return red('ERROR not found')
          return green('OK found')
  
      def _choose_profile_name(self):
          assert self.project or self.project_fail_details, \
              '_load_project() required'
  
          project_profile = None
          if self.project:
              project_profile = self.project.profile_name
  
          args_profile = getattr(self.args, 'profile', None)
  
          try:
              return Profile.pick_profile_name(args_profile, project_profile)
          except dbt.exceptions.DbtConfigError:
              pass
          # try to guess
  
          if self.raw_profile_data:
              profiles = [k for k in self.raw_profile_data if k != 'config']
              if len(profiles) == 0:
                  self.messages.append('The profiles.yml has no profiles')
              elif len(profiles) == 1:
                  self.messages.append(ONLY_PROFILE_MESSAGE.format(profiles[0]))
                  return profiles[0]
              else:
                  self.messages.append(MULTIPLE_PROFILE_MESSAGE.format(
                      '\n'.join(' - {}'.format(o) for o in profiles)
                  ))
          return None
  
      def _choose_target_name(self):
          has_raw_profile = (self.raw_profile_data and self.profile_name and
                             self.profile_name in self.raw_profile_data)
          if has_raw_profile:
              raw_profile = self.raw_profile_data[self.profile_name]
  
              target_name, _ = Profile.render_profile(
                  raw_profile, self.profile_name,
                  getattr(self.args, 'target', None), self.cli_vars
              )
              return target_name
          return None
  
      def _load_profile(self):
          if not os.path.exists(self.profile_path):
              self.profile_fail_details = FILE_NOT_FOUND
              self.messages.append(MISSING_PROFILE_MESSAGE.format(
                  path=self.profile_path, url=ProfileConfigDocs
              ))
              return red('ERROR not found')
  
          try:
              raw_profile_data = load_yaml_text(
                  dbt.clients.system.load_file_contents(self.profile_path)
              )
          except Exception:
              pass  # we'll report this when we try to load the profile for real
          else:
              if isinstance(raw_profile_data, dict):
                  self.raw_profile_data = raw_profile_data
  
          self.profile_name = self._choose_profile_name()
          self.target_name = self._choose_target_name()
          try:
              self.profile = Profile.from_args(self.args, self.profile_name)
          except dbt.exceptions.DbtConfigError as exc:
              self.profile_fail_details = str(exc)
              return red('ERROR invalid')
  
          return green('OK found and valid')
  
      def test_git(self):
          try:
              dbt.clients.system.run_cmd(os.getcwd(), ['git', '--help'])
          except dbt.exceptions.ExecutableError as exc:
              self.messages.append('Error from git --help: {!s}'.format(exc))
              return red('ERROR')
          return green('OK found')
  
      def test_dependencies(self):
          print('Required dependencies:')
          print(' - git [{}]'.format(self.test_git()))
          print('')
  
      def test_configuration(self):
          project_status = self._load_project()
          profile_status = self._load_profile()
          print('Configuration:')
          print('  profiles.yml file [{}]'.format(profile_status))
          print('  dbt_project.yml file [{}]'.format(project_status))
          # skip profile stuff if we can't find a profile name
          if self.profile_name is not None:
              print('  profile: {} [{}]'.format(self.profile_name,
                                                self._profile_found()))
              print('  target: {} [{}]'.format(self.target_name,
                                               self._target_found()))
          print('')
          self._log_project_fail()
          self._log_profile_fail()
  
      def _log_project_fail(self):
          if not self.project_fail_details:
              return
          if self.project_fail_details == FILE_NOT_FOUND:
              return
          print('Project loading failed for the following reason:')
          print(self.project_fail_details)
          print('')
  
      def _log_profile_fail(self):
          if not self.profile_fail_details:
              return
          if self.profile_fail_details == FILE_NOT_FOUND:
              return
          if self.profile_name is None:
              return  # we expect an error (no profile provided)
          print('Profile loading failed for the following reason:')
          print(self.profile_fail_details)
          print('')
  
      @staticmethod
      def attempt_connection(profile):
          """Return a string containing the error message, or None if there was
          no error.
          """
          register_adapter(profile)
          adapter = get_adapter(profile)
          try:
              with adapter.connection_named('debug'):
                  adapter.execute('select 1 as id')
          except Exception as exc:
              return COULD_NOT_CONNECT_MESSAGE.format(
                  err=str(exc),
                  url=ProfileConfigDocs,
              )
  
          return None
  
      def _connection_result(self):
          result = self.attempt_connection(self.profile)
          if result is not None:
              self.messages.append(result)
              return red('ERROR')
          return green('OK connection ok')
  
      def test_connection(self):
          if not self.profile:
              return
          print('Connection:')
          for k, v in self.profile.credentials.connection_info():
              print('  {}: {}'.format(k, v))
          print('  Connection test: {}'.format(self._connection_result()))
          print('')
  
      @classmethod
      def validate_connection(cls, target_dict):
          """Validate a connection dictionary. On error, raises a DbtConfigError.
          """
          target_name = 'test'
          # make a fake profile that we can parse
          profile_data = {
              'outputs': {
                  target_name: target_dict,
              },
          }
          # this will raise a DbtConfigError on failure
          profile = Profile.from_raw_profile_info(
              raw_profile=profile_data,
              profile_name='',
              target_override=target_name,
              cli_vars={},
          )
          result = cls.attempt_connection(profile)
          if result is not None:
              raise dbt.exceptions.DbtProfileError(
                  result,
                  result_type='connection_failure'
              )
  