# 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 os
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]

  # 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.
  if path != real_from_dir:
    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
    scope = {}
    try:
      import io
      with io.open(entries_filename, encoding='utf-8') as f:
        exec(f.read(), scope)
    except SyntaxError as e:
      SyntaxErrorToError(filename, e)
    all_directories = scope['entries'].keys()
    path_to_check = real_from_dir[len(path)+1:]
    while path_to_check:
      if path_to_check in all_directories:
        return path
      path_to_check = os.path.dirname(path_to_check)
    return None

  import logging
  logging.info('Found gclient root at ' + path)
  return path


def GetPrimarySolutionPath():
  """Returns the full path to the primary solution. (gclient_root + src)"""

  gclient_root = FindGclientRoot(os.getcwd())
  if not gclient_root:
    # Some projects might not use .gclient. Try to see whether we're in a git
    # checkout.
    top_dir = [os.getcwd()]
    def filter_fn(line):
      repo_root_path = os.path.normpath(line.rstrip('\n'))
      if os.path.exists(repo_root_path):
        top_dir[0] = repo_root_path
    try:
      CheckCallAndFilter(["git", "rev-parse", "--show-toplevel"],
                         print_stdout=False, filter_fn=filter_fn)
    except Exception:
      pass
    top_dir = top_dir[0]
    if os.path.exists(os.path.join(top_dir, 'buildtools')):
      return top_dir
    return None

  # 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)


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 not os.path.exists(buildtools_path):
    # Buildtools may be in the gclient root.
    gclient_root = FindGclientRoot(os.getcwd())
    buildtools_path = os.path.join(gclient_root, 'buildtools')
  return buildtools_path


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 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')
  env = {}
  exec(compile(open(gclient_config_file).read(), gclient_config_file, 'exec'),
       env)
  solutions = env.get('solutions', [])
  if solutions:
    return solutions[0].get('name')
  return None