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