mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-26 15:26:10 +03:00
207 lines
6.9 KiB
Python
207 lines
6.9 KiB
Python
|
#!/usr/bin/env python3
|
||
|
|
||
|
# Copyright 2018 The Chromium Authors
|
||
|
# 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.
|
||
|
* Downloads standalone binaries from [a possibly different version of Xcode].
|
||
|
|
||
|
The toolchain version can be overridden by setting MAC_TOOLCHAIN_REVISION with
|
||
|
the full revision, e.g. 9A235.
|
||
|
"""
|
||
|
|
||
|
import argparse
|
||
|
import os
|
||
|
import pkg_resources
|
||
|
import platform
|
||
|
import plistlib
|
||
|
import shutil
|
||
|
import subprocess
|
||
|
import sys
|
||
|
|
||
|
|
||
|
def LoadPList(path):
|
||
|
"""Loads Plist at |path| and returns it as a dictionary."""
|
||
|
with open(path, 'rb') as f:
|
||
|
return plistlib.load(f)
|
||
|
|
||
|
|
||
|
# This contains binaries from Xcode 14.0 14B47b along with the macOS 13 SDK
|
||
|
# (13.0 22A372). To build these packages, see comments in
|
||
|
# build/xcode_binaries.yaml
|
||
|
|
||
|
MAC_BINARIES_LABEL = 'infra_internal/ios/xcode/xcode_binaries/mac-amd64'
|
||
|
MAC_BINARIES_TAG = '14b47b'
|
||
|
|
||
|
# The toolchain will not be downloaded if the minimum OS version is not met. 19
|
||
|
# is the major version number for macOS 10.15. Xcode 14.0 14B47b only runs on
|
||
|
# macOS 12.4 and newer, but some bots are still running older OS versions. macOS
|
||
|
# 10.15.4, the OS minimum through Xcode 12.4, still seems to work.
|
||
|
MAC_MINIMUM_OS_VERSION = [19, 4]
|
||
|
|
||
|
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')
|
||
|
|
||
|
# Always integrity-check the entire SDK. Mac SDK packages are complex and often
|
||
|
# hit edge cases in cipd (eg https://crbug.com/1033987,
|
||
|
# https://crbug.com/915278), and generally when this happens it requires manual
|
||
|
# intervention to fix.
|
||
|
# Note the trailing \n!
|
||
|
PARANOID_MODE = '$ParanoidMode CheckIntegrity\n'
|
||
|
|
||
|
|
||
|
def PlatformMeetsHermeticXcodeRequirements():
|
||
|
if sys.platform != 'darwin':
|
||
|
return True
|
||
|
needed = MAC_MINIMUM_OS_VERSION
|
||
|
major_version = [int(v) for v in platform.release().split('.')[:len(needed)]]
|
||
|
return major_version >= needed
|
||
|
|
||
|
|
||
|
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().decode()
|
||
|
|
||
|
|
||
|
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 InstallXcodeBinaries():
|
||
|
"""Installs the Xcode binaries needed to build Chrome and accepts the license.
|
||
|
|
||
|
This is the replacement for InstallXcode that installs a trimmed down version
|
||
|
of Xcode that is OS-version agnostic.
|
||
|
"""
|
||
|
# First make sure the directory exists. It will serve as the cipd root. This
|
||
|
# also ensures that there will be no conflicts of cipd root.
|
||
|
binaries_root = os.path.join(TOOLCHAIN_ROOT, 'xcode_binaries')
|
||
|
if not os.path.exists(binaries_root):
|
||
|
os.makedirs(binaries_root)
|
||
|
|
||
|
# 'cipd ensure' is idempotent.
|
||
|
args = ['cipd', 'ensure', '-root', binaries_root, '-ensure-file', '-']
|
||
|
|
||
|
p = subprocess.Popen(args,
|
||
|
universal_newlines=True,
|
||
|
stdin=subprocess.PIPE,
|
||
|
stdout=subprocess.PIPE,
|
||
|
stderr=subprocess.PIPE)
|
||
|
stdout, stderr = p.communicate(input=PARANOID_MODE + MAC_BINARIES_LABEL +
|
||
|
' ' + MAC_BINARIES_TAG)
|
||
|
if p.returncode != 0:
|
||
|
print(stdout)
|
||
|
print(stderr)
|
||
|
RequestCipdAuthentication()
|
||
|
return 1
|
||
|
|
||
|
if sys.platform != 'darwin':
|
||
|
return 0
|
||
|
|
||
|
# Accept the license for this version of Xcode if it's newer than the
|
||
|
# currently accepted version.
|
||
|
cipd_xcode_version_plist_path = os.path.join(binaries_root,
|
||
|
'Contents/version.plist')
|
||
|
cipd_xcode_version_plist = LoadPList(cipd_xcode_version_plist_path)
|
||
|
cipd_xcode_version = cipd_xcode_version_plist['CFBundleShortVersionString']
|
||
|
|
||
|
cipd_license_path = os.path.join(binaries_root,
|
||
|
'Contents/Resources/LicenseInfo.plist')
|
||
|
cipd_license_plist = LoadPList(cipd_license_path)
|
||
|
cipd_license_version = cipd_license_plist['licenseID']
|
||
|
|
||
|
should_overwrite_license = True
|
||
|
current_license_path = '/Library/Preferences/com.apple.dt.Xcode.plist'
|
||
|
if os.path.exists(current_license_path):
|
||
|
current_license_plist = LoadPList(current_license_path)
|
||
|
xcode_version = current_license_plist.get(
|
||
|
'IDEXcodeVersionForAgreedToGMLicense')
|
||
|
if (xcode_version is not None and pkg_resources.parse_version(xcode_version)
|
||
|
>= pkg_resources.parse_version(cipd_xcode_version)):
|
||
|
should_overwrite_license = False
|
||
|
|
||
|
if not should_overwrite_license:
|
||
|
return 0
|
||
|
|
||
|
# Use puppet's sudoers script to accept the license if its available.
|
||
|
license_accept_script = '/usr/local/bin/xcode_accept_license.sh'
|
||
|
if os.path.exists(license_accept_script):
|
||
|
args = [
|
||
|
'sudo', license_accept_script, cipd_xcode_version, cipd_license_version
|
||
|
]
|
||
|
subprocess.check_call(args)
|
||
|
return 0
|
||
|
|
||
|
# Otherwise manually accept the license. This will prompt for sudo.
|
||
|
print('Accepting new Xcode license. Requires sudo.')
|
||
|
sys.stdout.flush()
|
||
|
args = [
|
||
|
'sudo', 'defaults', 'write', current_license_path,
|
||
|
'IDEXcodeVersionForAgreedToGMLicense', cipd_xcode_version
|
||
|
]
|
||
|
subprocess.check_call(args)
|
||
|
args = [
|
||
|
'sudo', 'defaults', 'write', current_license_path,
|
||
|
'IDELastGMLicenseAgreedTo', cipd_license_version
|
||
|
]
|
||
|
subprocess.check_call(args)
|
||
|
args = ['sudo', 'plutil', '-convert', 'xml1', current_license_path]
|
||
|
subprocess.check_call(args)
|
||
|
|
||
|
return 0
|
||
|
|
||
|
|
||
|
def main():
|
||
|
if not _UseHermeticToolchain():
|
||
|
print('Skipping Mac toolchain installation for mac')
|
||
|
return 0
|
||
|
|
||
|
parser = argparse.ArgumentParser(description='Download hermetic Xcode.')
|
||
|
args = parser.parse_args()
|
||
|
|
||
|
if not PlatformMeetsHermeticXcodeRequirements():
|
||
|
print('OS version does not support toolchain.')
|
||
|
return 0
|
||
|
|
||
|
return InstallXcodeBinaries()
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
sys.exit(main())
|