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