blob: 36e96f77bb5d75c4cca47a2da8efce1d21633c02 [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
Nico Weber09e0b382019-03-11 16:54:07 +000013import os
Dirk Pranke112a77f2019-03-12 01:50:42 +000014import sys
Nico Weber09e0b382019-03-11 16:54:07 +000015
16
17def FindGclientRoot(from_dir, filename='.gclient'):
18 """Tries to find the gclient root."""
19 real_from_dir = os.path.realpath(from_dir)
20 path = real_from_dir
21 while not os.path.exists(os.path.join(path, filename)):
22 split_path = os.path.split(path)
23 if not split_path[1]:
24 return None
25 path = split_path[0]
26
27 # If we did not find the file in the current directory, make sure we are in a
28 # sub directory that is controlled by this configuration.
29 if path != real_from_dir:
30 entries_filename = os.path.join(path, filename + '_entries')
31 if not os.path.exists(entries_filename):
Nico Weber09e0b382019-03-11 16:54:07 +000032 # If .gclient_entries does not exist, a previous call to gclient sync
33 # might have failed. In that case, we cannot verify that the .gclient
34 # is the one we want to use. In order to not to cause too much trouble,
35 # just issue a warning and return the path anyway.
Raul Tambreb946b232019-03-26 14:48:46 +000036 print(
37 "%s missing, %s file in parent directory %s might not be the file "
38 "you want to use." % (entries_filename, filename, path),
39 file=sys.stderr)
Nico Weber09e0b382019-03-11 16:54:07 +000040 return path
41 scope = {}
42 try:
43 import io
44 with io.open(entries_filename, encoding='utf-8') as f:
45 exec(f.read(), scope)
Raul Tambreb946b232019-03-26 14:48:46 +000046 except SyntaxError as e:
Nico Weber09e0b382019-03-11 16:54:07 +000047 SyntaxErrorToError(filename, e)
48 all_directories = scope['entries'].keys()
49 path_to_check = real_from_dir[len(path)+1:]
50 while path_to_check:
51 if path_to_check in all_directories:
52 return path
53 path_to_check = os.path.dirname(path_to_check)
54 return None
55
56 import logging
57 logging.info('Found gclient root at ' + path)
58 return path
59
60
61def GetPrimarySolutionPath():
62 """Returns the full path to the primary solution. (gclient_root + src)"""
63
64 gclient_root = FindGclientRoot(os.getcwd())
65 if not gclient_root:
66 # Some projects might not use .gclient. Try to see whether we're in a git
67 # checkout.
68 top_dir = [os.getcwd()]
69 def filter_fn(line):
70 repo_root_path = os.path.normpath(line.rstrip('\n'))
71 if os.path.exists(repo_root_path):
72 top_dir[0] = repo_root_path
73 try:
74 CheckCallAndFilter(["git", "rev-parse", "--show-toplevel"],
75 print_stdout=False, filter_fn=filter_fn)
76 except Exception:
77 pass
78 top_dir = top_dir[0]
79 if os.path.exists(os.path.join(top_dir, 'buildtools')):
80 return top_dir
81 return None
82
83 # Some projects' top directory is not named 'src'.
84 source_dir_name = GetGClientPrimarySolutionName(gclient_root) or 'src'
85 return os.path.join(gclient_root, source_dir_name)
86
87
88def GetBuildtoolsPath():
89 """Returns the full path to the buildtools directory.
90 This is based on the root of the checkout containing the current directory."""
91
92 # Overriding the build tools path by environment is highly unsupported and may
93 # break without warning. Do not rely on this for anything important.
94 override = os.environ.get('CHROMIUM_BUILDTOOLS_PATH')
95 if override is not None:
96 return override
97
98 primary_solution = GetPrimarySolutionPath()
99 if not primary_solution:
100 return None
101 buildtools_path = os.path.join(primary_solution, 'buildtools')
102 if not os.path.exists(buildtools_path):
103 # Buildtools may be in the gclient root.
104 gclient_root = FindGclientRoot(os.getcwd())
105 buildtools_path = os.path.join(gclient_root, 'buildtools')
106 return buildtools_path
107
108
109def GetBuildtoolsPlatformBinaryPath():
110 """Returns the full path to the binary directory for the current platform."""
111 buildtools_path = GetBuildtoolsPath()
112 if not buildtools_path:
113 return None
114
115 if sys.platform.startswith(('cygwin', 'win')):
116 subdir = 'win'
117 elif sys.platform == 'darwin':
118 subdir = 'mac'
119 elif sys.platform.startswith('linux'):
Raul Tambreb946b232019-03-26 14:48:46 +0000120 subdir = 'linux64'
Nico Weber09e0b382019-03-11 16:54:07 +0000121 else:
122 raise Error('Unknown platform: ' + sys.platform)
123 return os.path.join(buildtools_path, subdir)
124
125
126def GetExeSuffix():
127 """Returns '' or '.exe' depending on how executables work on this platform."""
Nico Weber09e0b382019-03-11 16:54:07 +0000128 if sys.platform.startswith(('cygwin', 'win')):
129 return '.exe'
130 return ''
131
132
133def GetGClientPrimarySolutionName(gclient_root_dir_path):
134 """Returns the name of the primary solution in the .gclient file specified."""
135 gclient_config_file = os.path.join(gclient_root_dir_path, '.gclient')
136 env = {}
Raul Tambreb946b232019-03-26 14:48:46 +0000137 exec(compile(open(gclient_config_file).read(), gclient_config_file, 'exec'),
138 env)
Nico Weber09e0b382019-03-11 16:54:07 +0000139 solutions = env.get('solutions', [])
140 if solutions:
141 return solutions[0].get('name')
142 return None