1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
# 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).
import functools
import logging
import os
import sys
import gclient_utils
import subprocess2
# TODO: Should fix these warnings.
# pylint: disable=line-too-long
@functools.lru_cache
def FindGclientRoot(from_dir, filename='.gclient'):
"""Tries to find the gclient root."""
real_from_dir = os.path.abspath(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 = set(
os.path.relpath(os.path.realpath(os.path.join(path, *k.split('/'))),
start=os.path.realpath(path))
for k in scope['entries'].keys())
path_to_check = os.path.relpath(os.path.realpath(real_from_dir),
start=os.path.realpath(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
@functools.lru_cache
def _GetPrimarySolutionPathInternal(cwd):
gclient_root = FindGclientRoot(cwd)
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 = cwd
try:
top_dir = subprocess2.check_output(
['git', 'rev-parse', '--show-toplevel'], stderr=subprocess2.DEVNULL)
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 GetPrimarySolutionPath():
"""Returns the full path to the primary solution. (gclient_root + src)"""
return _GetPrimarySolutionPathInternal(os.getcwd())
@functools.lru_cache
def _GetBuildtoolsPathInternal(cwd, override):
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 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')
return _GetBuildtoolsPathInternal(os.getcwd(), override)
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 ''
@functools.lru_cache
def _GetGClientSolutions(gclient_root_dir_path):
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)
return env.get('solutions', [])
def GetGClientPrimarySolutionName(gclient_root_dir_path):
"""Returns the name of the primary solution in the .gclient file specified."""
solutions = _GetGClientSolutions(gclient_root_dir_path)
if solutions:
return solutions[0].get('name')
return None
def GetGClientPrimarySolutionURL(gclient_root_dir_path):
"""Returns the URL of the primary solution in the .gclient file specified."""
solutions = _GetGClientSolutions(gclient_root_dir_path)
if solutions:
return solutions[0].get('url')
return None
|