|  | # 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. | 
|  | """The `macos_sdk` module provides safe functions to access a semi-hermetic | 
|  | XCode installation. | 
|  |  | 
|  | Available only to Google-run bots.""" | 
|  |  | 
|  | from contextlib import contextmanager | 
|  |  | 
|  | from recipe_engine import recipe_api | 
|  |  | 
|  |  | 
|  | class MacOSSDKApi(recipe_api.RecipeApi): | 
|  | """API for using OS X SDK distributed via CIPD.""" | 
|  |  | 
|  | def __init__(self, sdk_properties, *args, **kwargs): | 
|  | super(MacOSSDKApi, self).__init__(*args, **kwargs) | 
|  |  | 
|  | self._sdk_version = sdk_properties['sdk_version'].lower() | 
|  | self._tool_package = sdk_properties['tool_package'] | 
|  | self._tool_version = sdk_properties['tool_version'] | 
|  |  | 
|  | @contextmanager | 
|  | def __call__(self): | 
|  | """Sets up the XCode SDK environment. | 
|  |  | 
|  | This call is a no-op on non-Mac platforms. | 
|  |  | 
|  | This will deploy the helper tool and the XCode.app bundle at | 
|  | `[START_DIR]/cache/macos_sdk`. | 
|  |  | 
|  | To avoid machines rebuilding these on every run, set up a named cache in | 
|  | your cr-buildbucket.cfg file like: | 
|  |  | 
|  | caches: { | 
|  | # Cache for mac_toolchain tool and XCode.app | 
|  | name: "macos_sdk" | 
|  | path: "macos_sdk" | 
|  | } | 
|  |  | 
|  | If you have builders which e.g. use a non-current SDK, you can give them | 
|  | a uniqely named cache: | 
|  |  | 
|  | caches: { | 
|  | # Cache for N-1 version mac_toolchain tool and XCode.app | 
|  | name: "macos_sdk_old" | 
|  | path: "macos_sdk" | 
|  | } | 
|  |  | 
|  | Usage: | 
|  | with api.macos_sdk(): | 
|  | # sdk with mac build bits | 
|  |  | 
|  | Raises: | 
|  | StepFailure or InfraFailure. | 
|  | """ | 
|  | if not self.m.platform.is_mac: | 
|  | yield | 
|  | return | 
|  |  | 
|  | try: | 
|  | with self.m.context(infra_steps=True): | 
|  | sdk_dir = self._ensure_sdk() | 
|  | self.m.step('select XCode', | 
|  | ['sudo', 'xcode-select', '--switch', sdk_dir]) | 
|  | yield | 
|  | finally: | 
|  | with self.m.context(infra_steps=True): | 
|  | self.m.step('reset XCode', ['sudo', 'xcode-select', '--reset']) | 
|  |  | 
|  | def _ensure_sdk(self): | 
|  | """Ensures the mac_toolchain tool and MacOS SDK packages are installed. | 
|  |  | 
|  | Returns Path to the installed sdk app bundle.""" | 
|  | cache_dir = self.m.path['cache'].join('macos_sdk') | 
|  | pkgs = self.m.cipd.EnsureFile() | 
|  | pkgs.add_package(self._tool_package, self._tool_version) | 
|  | self.m.cipd.ensure(cache_dir, pkgs) | 
|  |  | 
|  | sdk_dir = cache_dir.join('XCode.app') | 
|  | self.m.step('install xcode', [ | 
|  | cache_dir.join('mac_toolchain'), | 
|  | 'install', | 
|  | '-kind', | 
|  | 'mac', | 
|  | '-xcode-version', | 
|  | self._sdk_version, | 
|  | '-output-dir', | 
|  | sdk_dir, | 
|  | ]) | 
|  | return sdk_dir |