blob: 998a0b39c4cd5a182a3c10545f9ed17778a7c4b3 [file] [log] [blame]
Nico Weber09e0b382019-03-11 16:54:07 +00001# 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
5# This file is imported by various thin wrappers (around gn, clang-format, ...),
6# so it's meant to import very quickly. To keep it that way don't add more
Dirk Pranke112a77f2019-03-12 01:50:42 +00007# code, and even more importantly don't add more toplevel import statements,
8# particularly for modules that are not builtin (see sys.builtin_modules_names,
9# os isn't built in, but it's essential to this file).
Raul Tambreb946b232019-03-26 14:48:46 +000010
11from __future__ import print_function
12
Robert Liao7211cf62019-09-25 00:53:44 +000013import gclient_utils
Edward Lemur84b5f9a2020-01-08 20:06:51 +000014import logging
Nico Weber09e0b382019-03-11 16:54:07 +000015import os
Edward Lemur84b5f9a2020-01-08 20:06:51 +000016import subprocess2
Dirk Pranke112a77f2019-03-12 01:50:42 +000017import sys
Nico Weber09e0b382019-03-11 16:54:07 +000018
19
20def FindGclientRoot(from_dir, filename='.gclient'):
21 """Tries to find the gclient root."""
22 real_from_dir = os.path.realpath(from_dir)
23 path = real_from_dir
24 while not os.path.exists(os.path.join(path, filename)):
25 split_path = os.path.split(path)
26 if not split_path[1]:
27 return None
28 path = split_path[0]
29
Edward Lemur84b5f9a2020-01-08 20:06:51 +000030 logging.info('Found gclient root at ' + path)
31
32 if path == real_from_dir:
33 return path
34
Nico Weber09e0b382019-03-11 16:54:07 +000035 # If we did not find the file in the current directory, make sure we are in a
36 # sub directory that is controlled by this configuration.
Edward Lemur84b5f9a2020-01-08 20:06:51 +000037 entries_filename = os.path.join(path, filename + '_entries')
38 if not os.path.exists(entries_filename):
39 # If .gclient_entries does not exist, a previous call to gclient sync
40 # might have failed. In that case, we cannot verify that the .gclient
41 # is the one we want to use. In order to not to cause too much trouble,
42 # just issue a warning and return the path anyway.
43 print(
44 "%s missing, %s file in parent directory %s might not be the file "
45 "you want to use." % (entries_filename, filename, path),
46 file=sys.stderr)
47 return path
Nico Weber09e0b382019-03-11 16:54:07 +000048
Edward Lemur84b5f9a2020-01-08 20:06:51 +000049 entries_content = gclient_utils.FileRead(entries_filename)
50 scope = {}
51 try:
52 exec(entries_content, scope)
53 except (SyntaxError, Exception) as e:
54 gclient_utils.SyntaxErrorToError(filename, e)
55
56 all_directories = scope['entries'].keys()
57 path_to_check = os.path.relpath(real_from_dir, path)
58 while path_to_check:
59 if path_to_check in all_directories:
60 return path
61 path_to_check = os.path.dirname(path_to_check)
62
63 return None
Nico Weber09e0b382019-03-11 16:54:07 +000064
65
66def GetPrimarySolutionPath():
67 """Returns the full path to the primary solution. (gclient_root + src)"""
68
69 gclient_root = FindGclientRoot(os.getcwd())
Edward Lemur84b5f9a2020-01-08 20:06:51 +000070 if gclient_root:
71 # Some projects' top directory is not named 'src'.
72 source_dir_name = GetGClientPrimarySolutionName(gclient_root) or 'src'
73 return os.path.join(gclient_root, source_dir_name)
Nico Weber09e0b382019-03-11 16:54:07 +000074
Edward Lemur84b5f9a2020-01-08 20:06:51 +000075 # Some projects might not use .gclient. Try to see whether we're in a git
76 # checkout that contains a 'buildtools' subdir.
77 top_dir = os.getcwd()
78 try:
79 top_dir = subprocess2.check_output(
80 ['git', 'rev-parse', '--show-toplevel'])
81 if sys.version_info.major == 3:
82 top_dir = top_dir.decode('utf-8', 'replace')
83 top_dir = os.path.normpath(top_dir.strip())
84 except subprocess2.CalledProcessError:
85 pass
86
87 if os.path.exists(os.path.join(top_dir, 'buildtools')):
88 return top_dir
89 return None
Nico Weber09e0b382019-03-11 16:54:07 +000090
91
92def GetBuildtoolsPath():
93 """Returns the full path to the buildtools directory.
94 This is based on the root of the checkout containing the current directory."""
95
96 # Overriding the build tools path by environment is highly unsupported and may
97 # break without warning. Do not rely on this for anything important.
98 override = os.environ.get('CHROMIUM_BUILDTOOLS_PATH')
99 if override is not None:
100 return override
101
102 primary_solution = GetPrimarySolutionPath()
103 if not primary_solution:
104 return None
Edward Lemur84b5f9a2020-01-08 20:06:51 +0000105
Nico Weber09e0b382019-03-11 16:54:07 +0000106 buildtools_path = os.path.join(primary_solution, 'buildtools')
Edward Lemur84b5f9a2020-01-08 20:06:51 +0000107 if os.path.exists(buildtools_path):
108 return buildtools_path
109
110 # buildtools may be in the gclient root.
111 gclient_root = FindGclientRoot(os.getcwd())
112 buildtools_path = os.path.join(gclient_root, 'buildtools')
113 if os.path.exists(buildtools_path):
114 return buildtools_path
115
116 return None
Nico Weber09e0b382019-03-11 16:54:07 +0000117
118
119def GetBuildtoolsPlatformBinaryPath():
120 """Returns the full path to the binary directory for the current platform."""
121 buildtools_path = GetBuildtoolsPath()
122 if not buildtools_path:
123 return None
124
125 if sys.platform.startswith(('cygwin', 'win')):
126 subdir = 'win'
127 elif sys.platform == 'darwin':
128 subdir = 'mac'
129 elif sys.platform.startswith('linux'):
Raul Tambreb946b232019-03-26 14:48:46 +0000130 subdir = 'linux64'
Nico Weber09e0b382019-03-11 16:54:07 +0000131 else:
Edward Lemur84b5f9a2020-01-08 20:06:51 +0000132 raise gclient_utils.Error('Unknown platform: ' + sys.platform)
Nico Weber09e0b382019-03-11 16:54:07 +0000133 return os.path.join(buildtools_path, subdir)
134
135
136def GetExeSuffix():
137 """Returns '' or '.exe' depending on how executables work on this platform."""
Nico Weber09e0b382019-03-11 16:54:07 +0000138 if sys.platform.startswith(('cygwin', 'win')):
139 return '.exe'
140 return ''
141
142
143def GetGClientPrimarySolutionName(gclient_root_dir_path):
144 """Returns the name of the primary solution in the .gclient file specified."""
145 gclient_config_file = os.path.join(gclient_root_dir_path, '.gclient')
Edward Lemur84b5f9a2020-01-08 20:06:51 +0000146 gclient_config_contents = gclient_utils.FileRead(gclient_config_file)
Nico Weber09e0b382019-03-11 16:54:07 +0000147 env = {}
Edward Lemur84b5f9a2020-01-08 20:06:51 +0000148 exec(gclient_config_contents, env)
Nico Weber09e0b382019-03-11 16:54:07 +0000149 solutions = env.get('solutions', [])
150 if solutions:
151 return solutions[0].get('name')
152 return None