|  | # 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. | 
|  |  | 
|  | """Functions to use fixed xcode installations. | 
|  |  | 
|  | The cost of installing xcode from cold caches is prohibitely high for the | 
|  | Flutter Devicelab tasks. This module provide functions to use semi-hermetic | 
|  | Xcode installations pre-installed on Devicelab bots. | 
|  |  | 
|  | XCode build version number. Internally maps to an XCode build id like '9c40b'. | 
|  | See: | 
|  | https://chrome-infra-packages.appspot.com/p/flutter_internal/ios/xcode/mac/+/ | 
|  | for an up to date list of the latest SDK builds. | 
|  | """ | 
|  |  | 
|  | from contextlib import contextmanager | 
|  |  | 
|  | from recipe_engine import recipe_api | 
|  |  | 
|  |  | 
|  | class DevicelabOSXSDKApi(recipe_api.RecipeApi): | 
|  | """API for using OS X SDK distributed via CIPD.""" | 
|  |  | 
|  | def __init__(self, sdk_properties, *args, **kwargs): | 
|  | super(DevicelabOSXSDKApi, self).__init__(*args, **kwargs) | 
|  | self._sdk_properties = sdk_properties | 
|  | self._sdk_version = None | 
|  | self._tool_pkg = 'infra/tools/mac_toolchain/${platform}' | 
|  | self._tool_ver = 'latest' | 
|  |  | 
|  | def initialize(self): | 
|  | """Initializes xcode, and ios versions. | 
|  |  | 
|  | Versions are passed as recipe properties. | 
|  | """ | 
|  | if not self.m.platform.is_mac: | 
|  | return | 
|  |  | 
|  | if 'sdk_version' in self._sdk_properties: | 
|  | self._sdk_version = self._sdk_properties['sdk_version'].lower() | 
|  |  | 
|  | @contextmanager | 
|  | def __call__(self, kind): | 
|  | """Sets up the XCode SDK environment. | 
|  |  | 
|  | Is a no-op on non-mac platforms. | 
|  |  | 
|  | This will deploy the helper tool and the XCode.app bundle at | 
|  | `/opt/flutter/xcode/<version>`. | 
|  |  | 
|  | Usage: | 
|  | with api.devicelab_osx_sdk('mac'): | 
|  | # sdk with mac build bits | 
|  |  | 
|  | with api.devicelab_osx_sdk('ios'): | 
|  | # sdk with mac+iOS build bits | 
|  |  | 
|  | Args: | 
|  | kind ('mac'|'ios'): How the SDK should be configured. iOS includes the | 
|  | base XCode distribution, as well as the iOS simulators (which can be | 
|  | quite large). | 
|  |  | 
|  | Raises: | 
|  | StepFailure or InfraFailure. | 
|  | """ | 
|  | assert kind in ('mac', 'ios'), 'Invalid kind %r' % (kind,) | 
|  | if not self.m.platform.is_mac: | 
|  | yield | 
|  | return | 
|  |  | 
|  | try: | 
|  | with self.m.context(infra_steps=True): | 
|  | app = '/opt/flutter/xcode/%s/XCode.app' % self._sdk_version | 
|  | self._ensure_sdk(kind, app) | 
|  | self.m.step('select XCode', ['sudo', 'xcode-select', '--switch', app]) | 
|  | self.m.step('list simulators', ['xcrun', 'simctl', 'list']) | 
|  | yield | 
|  | finally: | 
|  | with self.m.context(infra_steps=True): | 
|  | self.m.step('reset XCode', ['sudo', 'xcode-select', '--reset']) | 
|  |  | 
|  | def _ensure_sdk(self, kind, app): | 
|  | """Ensures the mac_toolchain tool and OS X SDK packages are installed.""" | 
|  | tool_dir = self.m.path.mkdtemp().join('osx_sdk') | 
|  | ef = self.m.cipd.EnsureFile() | 
|  | ef.add_package(self._tool_pkg, self._tool_ver) | 
|  | self.m.cipd.ensure(tool_dir, ef) | 
|  | self.m.step( | 
|  | 'install xcode', [ | 
|  | tool_dir.join('mac_toolchain'), | 
|  | 'install', | 
|  | '-kind', | 
|  | kind, | 
|  | '-xcode-version', | 
|  | self._sdk_version, | 
|  | '-output-dir', | 
|  | app, | 
|  | '-cipd-package-prefix', | 
|  | 'flutter_internal/ios/xcode', | 
|  | ] | 
|  | ) |