text: # Copyright 2019 The Chromium Authors. All rights reserved.
  # Use of this source code is governed by a BSD-style license that can be
  # found in the LICENSE file.
  
  # This file is imported by various thin wrappers (around gn, clang-format, ...),
  # so it's meant to import very quickly. To keep it that way don't add more
  # code, and even more importantly don't add more toplevel import statements,
  # particularly for modules that are not builtin (see sys.builtin_modules_names,
  # os isn't built in, but it's essential to this file).
  
  from __future__ import print_function
  
  import gclient_utils
  import logging
  import os
  import subprocess2
  import sys
  
  
  def FindGclientRoot(from_dir, filename='.gclient'):
    """Tries to find the gclient root."""
    real_from_dir = os.path.realpath(from_dir)
    path = real_from_dir
    while not os.path.exists(os.path.join(path, filename)):
      split_path = os.path.split(path)
      if not split_path[1]:
        return None
      path = split_path[0]
  
    logging.info('Found gclient root at ' + path)
  
    if path == real_from_dir:
      return path
  
    # If we did not find the file in the current directory, make sure we are in a
    # sub directory that is controlled by this configuration.
    entries_filename = os.path.join(path, filename + '_entries')
    if not os.path.exists(entries_filename):
      # If .gclient_entries does not exist, a previous call to gclient sync
      # might have failed. In that case, we cannot verify that the .gclient
      # is the one we want to use. In order to not to cause too much trouble,
      # just issue a warning and return the path anyway.
      print(
          "%s missing, %s file in parent directory %s might not be the file "
          "you want to use." % (entries_filename, filename, path),
          file=sys.stderr)
      return path
  
    entries_content = gclient_utils.FileRead(entries_filename)
    scope = {}
    try:
      exec(entries_content, scope)
    except (SyntaxError, Exception) as e:
      gclient_utils.SyntaxErrorToError(filename, e)
  
    all_directories = scope['entries'].keys()
    path_to_check = os.path.relpath(real_from_dir, path)
    while path_to_check:
      if path_to_check in all_directories:
        return path
      path_to_check = os.path.dirname(path_to_check)
  
    return None
  
  
  def GetPrimarySolutionPath():
    """Returns the full path to the primary solution. (gclient_root + src)"""
  
    gclient_root = FindGclientRoot(os.getcwd())
    if gclient_root:
      # Some projects' top directory is not named 'src'.
      source_dir_name = GetGClientPrimarySolutionName(gclient_root) or 'src'
      return os.path.join(gclient_root, source_dir_name)
  
    # Some projects might not use .gclient. Try to see whether we're in a git
    # checkout that contains a 'buildtools' subdir.
    top_dir = os.getcwd()
    try:
      top_dir = subprocess2.check_output(
          ['git', 'rev-parse', '--show-toplevel'])
      if sys.version_info.major == 3:
        top_dir = top_dir.decode('utf-8', 'replace')
      top_dir = os.path.normpath(top_dir.strip())
    except subprocess2.CalledProcessError:
      pass
  
    if os.path.exists(os.path.join(top_dir, 'buildtools')):
      return top_dir
    return None
  
  
  def GetBuildtoolsPath():
    """Returns the full path to the buildtools directory.
    This is based on the root of the checkout containing the current directory."""
  
    # Overriding the build tools path by environment is highly unsupported and may
    # break without warning.  Do not rely on this for anything important.
    override = os.environ.get('CHROMIUM_BUILDTOOLS_PATH')
    if override is not None:
      return override
  
    primary_solution = GetPrimarySolutionPath()
    if not primary_solution:
      return None
  
    buildtools_path = os.path.join(primary_solution, 'buildtools')
    if os.path.exists(buildtools_path):
      return buildtools_path
  
    # buildtools may be in the gclient root.
    gclient_root = FindGclientRoot(os.getcwd())
    buildtools_path = os.path.join(gclient_root, 'buildtools')
    if os.path.exists(buildtools_path):
      return buildtools_path
  
    return None
  
  
  def GetBuildtoolsPlatformBinaryPath():
    """Returns the full path to the binary directory for the current platform."""
    buildtools_path = GetBuildtoolsPath()
    if not buildtools_path:
      return None
  
    if sys.platform.startswith(('cygwin', 'win')):
      subdir = 'win'
    elif sys.platform == 'darwin':
      subdir = 'mac'
    elif sys.platform.startswith('linux'):
      subdir = 'linux64'
    else:
      raise gclient_utils.Error('Unknown platform: ' + sys.platform)
    return os.path.join(buildtools_path, subdir)
  
  
  def GetExeSuffix():
    """Returns '' or '.exe' depending on how executables work on this platform."""
    if sys.platform.startswith(('cygwin', 'win')):
      return '.exe'
    return ''
  
  
  def GetGClientPrimarySolutionName(gclient_root_dir_path):
    """Returns the name of the primary solution in the .gclient file specified."""
    gclient_config_file = os.path.join(gclient_root_dir_path, '.gclient')
    gclient_config_contents = gclient_utils.FileRead(gclient_config_file)
    env = {}
    exec(gclient_config_contents, env)
    solutions = env.get('solutions', [])
    if solutions:
      return solutions[0].get('name')
    return None
  