summaryrefslogtreecommitdiff
path: root/deps/v8/build/mac_toolchain.py
blob: 87ed2568124ac59034f8746e503166bad09f0c5b (plain)
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
#!/usr/bin/env python
# Copyright 2018 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.

"""
If should_use_hermetic_xcode.py emits "1", and the current toolchain is out of
date:
  * Downloads the hermetic mac toolchain
    * Requires CIPD authentication. Run `cipd auth-login`, use Google account.
  * Accepts the license.
    * If xcode-select and xcodebuild are not passwordless in sudoers, requires
      user interaction.

The toolchain version can be overridden by setting MAC_TOOLCHAIN_REVISION with
the full revision, e.g. 9A235.
"""

import os
import platform
import shutil
import subprocess
import sys


# This can be changed after running:
#    mac_toolchain upload -xcode-path path/to/Xcode.app
MAC_TOOLCHAIN_VERSION = '9E501'

# The toolchain will not be downloaded if the minimum OS version is not met.
# 17 is the major version number for macOS 10.13.
# 9E145 (Xcode 9.3) only runs on 10.13.2 and newer.
MAC_MINIMUM_OS_VERSION = 17

MAC_TOOLCHAIN_INSTALLER = 'mac_toolchain'

# Absolute path to src/ directory.
REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Absolute path to a file with gclient solutions.
GCLIENT_CONFIG = os.path.join(os.path.dirname(REPO_ROOT), '.gclient')

BASE_DIR = os.path.abspath(os.path.dirname(__file__))
TOOLCHAIN_ROOT = os.path.join(BASE_DIR, 'mac_files')
TOOLCHAIN_BUILD_DIR = os.path.join(TOOLCHAIN_ROOT, 'Xcode.app')
STAMP_FILE = os.path.join(TOOLCHAIN_ROOT, 'toolchain_build_revision')


def PlatformMeetsHermeticXcodeRequirements():
  major_version = int(platform.release().split('.')[0])
  return major_version >= MAC_MINIMUM_OS_VERSION


def _UseHermeticToolchain():
  current_dir = os.path.dirname(os.path.realpath(__file__))
  script_path = os.path.join(current_dir, 'mac/should_use_hermetic_xcode.py')
  proc = subprocess.Popen([script_path, 'mac'], stdout=subprocess.PIPE)
  return '1' in proc.stdout.readline()


def RequestCipdAuthentication():
  """Requests that the user authenticate to access Xcode CIPD packages."""

  print 'Access to Xcode CIPD package requires authentication.'
  print '-----------------------------------------------------------------'
  print
  print 'You appear to be a Googler.'
  print
  print 'I\'m sorry for the hassle, but you may need to do a one-time manual'
  print 'authentication. Please run:'
  print
  print '    cipd auth-login'
  print
  print 'and follow the instructions.'
  print
  print 'NOTE: Use your google.com credentials, not chromium.org.'
  print
  print '-----------------------------------------------------------------'
  print
  sys.stdout.flush()


def PrintError(message):
  # Flush buffers to ensure correct output ordering.
  sys.stdout.flush()
  sys.stderr.write(message + '\n')
  sys.stderr.flush()


def InstallXcode(xcode_build_version, installer_cmd, xcode_app_path):
  """Installs the requested Xcode build version.

  Args:
    xcode_build_version: (string) Xcode build version to install.
    installer_cmd: (string) Path to mac_toolchain command to install Xcode.
      See https://chromium.googlesource.com/infra/infra/+/master/go/src/infra/cmd/mac_toolchain/
    xcode_app_path: (string) Path to install the contents of Xcode.app.

  Returns:
    True if installation was successful. False otherwise.
  """
  args = [
      installer_cmd, 'install',
      '-kind', 'mac',
      '-xcode-version', xcode_build_version.lower(),
      '-output-dir', xcode_app_path,
  ]

  # Buildbot slaves need to use explicit credentials. LUCI bots should NOT set
  # this variable.
  creds = os.environ.get('MAC_TOOLCHAIN_CREDS')
  if creds:
    args.extend(['--service-account-json', creds])

  try:
    subprocess.check_call(args)
  except subprocess.CalledProcessError as e:
    PrintError('Xcode build version %s failed to install: %s\n' % (
        xcode_build_version, e))
    RequestCipdAuthentication()
    return False
  except OSError as e:
    PrintError(('Xcode installer "%s" failed to execute'
                ' (not on PATH or not installed).') % installer_cmd)
    return False

  return True


def main():
  if sys.platform != 'darwin':
    return 0

  if not _UseHermeticToolchain():
    print 'Skipping Mac toolchain installation for mac'
    return 0

  if not PlatformMeetsHermeticXcodeRequirements():
    print 'OS version does not support toolchain.'
    return 0

  toolchain_version = os.environ.get('MAC_TOOLCHAIN_REVISION',
                                      MAC_TOOLCHAIN_VERSION)

  # On developer machines, mac_toolchain tool is provided by
  # depot_tools. On the bots, the recipe is responsible for installing
  # it and providing the path to the executable.
  installer_cmd = os.environ.get('MAC_TOOLCHAIN_INSTALLER',
                                 MAC_TOOLCHAIN_INSTALLER)

  toolchain_root = TOOLCHAIN_ROOT
  xcode_app_path = TOOLCHAIN_BUILD_DIR
  stamp_file = STAMP_FILE

  # Delete the old "hermetic" installation if detected.
  # TODO(crbug.com/797051): remove this once the old "hermetic" solution is no
  # longer in use.
  if os.path.exists(stamp_file):
    print 'Detected old hermetic installation at %s. Deleting.' % (
      toolchain_root)
    shutil.rmtree(toolchain_root)

  success = InstallXcode(toolchain_version, installer_cmd, xcode_app_path)
  if not success:
    return 1

  return 0


if __name__ == '__main__':
  sys.exit(main())