gclient_paths.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. # Copyright 2019 The Chromium Authors. All rights reserved.
  2. # Use of this source code is governed by a BSD-style license that can be
  3. # found in the LICENSE file.
  4. # This file is imported by various thin wrappers (around gn, clang-format, ...),
  5. # so it's meant to import very quickly. To keep it that way don't add more
  6. # code, and even more importantly don't add more toplevel import statements,
  7. # particularly for modules that are not builtin (see sys.builtin_modules_names,
  8. # os isn't built in, but it's essential to this file).
  9. from __future__ import print_function
  10. import gclient_utils
  11. import os
  12. import sys
  13. def FindGclientRoot(from_dir, filename='.gclient'):
  14. """Tries to find the gclient root."""
  15. real_from_dir = os.path.realpath(from_dir)
  16. path = real_from_dir
  17. while not os.path.exists(os.path.join(path, filename)):
  18. split_path = os.path.split(path)
  19. if not split_path[1]:
  20. return None
  21. path = split_path[0]
  22. # If we did not find the file in the current directory, make sure we are in a
  23. # sub directory that is controlled by this configuration.
  24. if path != real_from_dir:
  25. entries_filename = os.path.join(path, filename + '_entries')
  26. if not os.path.exists(entries_filename):
  27. # If .gclient_entries does not exist, a previous call to gclient sync
  28. # might have failed. In that case, we cannot verify that the .gclient
  29. # is the one we want to use. In order to not to cause too much trouble,
  30. # just issue a warning and return the path anyway.
  31. print(
  32. "%s missing, %s file in parent directory %s might not be the file "
  33. "you want to use." % (entries_filename, filename, path),
  34. file=sys.stderr)
  35. return path
  36. scope = {}
  37. try:
  38. import io
  39. with io.open(entries_filename, encoding='utf-8') as f:
  40. exec(f.read(), scope)
  41. except SyntaxError as e:
  42. SyntaxErrorToError(filename, e)
  43. all_directories = scope['entries'].keys()
  44. path_to_check = real_from_dir[len(path)+1:]
  45. while path_to_check:
  46. if path_to_check in all_directories:
  47. return path
  48. path_to_check = os.path.dirname(path_to_check)
  49. return None
  50. import logging
  51. logging.info('Found gclient root at ' + path)
  52. return path
  53. def GetPrimarySolutionPath():
  54. """Returns the full path to the primary solution. (gclient_root + src)"""
  55. gclient_root = FindGclientRoot(os.getcwd())
  56. if not gclient_root:
  57. # Some projects might not use .gclient. Try to see whether we're in a git
  58. # checkout.
  59. top_dir = [os.getcwd()]
  60. def filter_fn(line):
  61. repo_root_path = os.path.normpath(line.rstrip('\n'))
  62. if os.path.exists(repo_root_path):
  63. top_dir[0] = repo_root_path
  64. try:
  65. gclient_utils.CheckCallAndFilter(["git", "rev-parse", "--show-toplevel"],
  66. print_stdout=False,
  67. filter_fn=filter_fn)
  68. except Exception:
  69. pass
  70. top_dir = top_dir[0]
  71. if os.path.exists(os.path.join(top_dir, 'buildtools')):
  72. return top_dir
  73. return None
  74. # Some projects' top directory is not named 'src'.
  75. source_dir_name = GetGClientPrimarySolutionName(gclient_root) or 'src'
  76. return os.path.join(gclient_root, source_dir_name)
  77. def GetBuildtoolsPath():
  78. """Returns the full path to the buildtools directory.
  79. This is based on the root of the checkout containing the current directory."""
  80. # Overriding the build tools path by environment is highly unsupported and may
  81. # break without warning. Do not rely on this for anything important.
  82. override = os.environ.get('CHROMIUM_BUILDTOOLS_PATH')
  83. if override is not None:
  84. return override
  85. primary_solution = GetPrimarySolutionPath()
  86. if not primary_solution:
  87. return None
  88. buildtools_path = os.path.join(primary_solution, 'buildtools')
  89. if not os.path.exists(buildtools_path):
  90. # Buildtools may be in the gclient root.
  91. gclient_root = FindGclientRoot(os.getcwd())
  92. buildtools_path = os.path.join(gclient_root, 'buildtools')
  93. return buildtools_path
  94. def GetBuildtoolsPlatformBinaryPath():
  95. """Returns the full path to the binary directory for the current platform."""
  96. buildtools_path = GetBuildtoolsPath()
  97. if not buildtools_path:
  98. return None
  99. if sys.platform.startswith(('cygwin', 'win')):
  100. subdir = 'win'
  101. elif sys.platform == 'darwin':
  102. subdir = 'mac'
  103. elif sys.platform.startswith('linux'):
  104. subdir = 'linux64'
  105. else:
  106. raise Error('Unknown platform: ' + sys.platform)
  107. return os.path.join(buildtools_path, subdir)
  108. def GetExeSuffix():
  109. """Returns '' or '.exe' depending on how executables work on this platform."""
  110. if sys.platform.startswith(('cygwin', 'win')):
  111. return '.exe'
  112. return ''
  113. def GetGClientPrimarySolutionName(gclient_root_dir_path):
  114. """Returns the name of the primary solution in the .gclient file specified."""
  115. gclient_config_file = os.path.join(gclient_root_dir_path, '.gclient')
  116. env = {}
  117. exec(compile(open(gclient_config_file).read(), gclient_config_file, 'exec'),
  118. env)
  119. solutions = env.get('solutions', [])
  120. if solutions:
  121. return solutions[0].get('name')
  122. return None