• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2018 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"""The `macos_sdk` module provides safe functions to access a semi-hermetic
5XCode installation.
6
7Available only to Google-run bots."""
8
9from contextlib import contextmanager
10
11from recipe_engine import recipe_api
12
13
14class MacOSSDKApi(recipe_api.RecipeApi):
15  """API for using OS X SDK distributed via CIPD."""
16
17  def __init__(self, sdk_properties, *args, **kwargs):
18    super(MacOSSDKApi, self).__init__(*args, **kwargs)
19
20    self._sdk_version = sdk_properties['sdk_version'].lower()
21    self._tool_package = sdk_properties['tool_package']
22    self._tool_version = sdk_properties['tool_version']
23
24  @contextmanager
25  def __call__(self):
26    """Sets up the XCode SDK environment.
27
28    This call is a no-op on non-Mac platforms.
29
30    This will deploy the helper tool and the XCode.app bundle at
31    `[START_DIR]/cache/macos_sdk`.
32
33    To avoid machines rebuilding these on every run, set up a named cache in
34    your cr-buildbucket.cfg file like:
35
36        caches: {
37          # Cache for mac_toolchain tool and XCode.app
38          name: "macos_sdk"
39          path: "macos_sdk"
40        }
41
42    If you have builders which e.g. use a non-current SDK, you can give them
43    a uniqely named cache:
44
45        caches: {
46          # Cache for N-1 version mac_toolchain tool and XCode.app
47          name: "macos_sdk_old"
48          path: "macos_sdk"
49        }
50
51    Usage:
52      with api.macos_sdk():
53        # sdk with mac build bits
54
55    Raises:
56        StepFailure or InfraFailure.
57    """
58    if not self.m.platform.is_mac:
59      yield
60      return
61
62    try:
63      with self.m.context(infra_steps=True):
64        sdk_dir = self._ensure_sdk()
65        self.m.step('select XCode',
66                    ['sudo', 'xcode-select', '--switch', sdk_dir])
67      yield
68    finally:
69      with self.m.context(infra_steps=True):
70        self.m.step('reset XCode', ['sudo', 'xcode-select', '--reset'])
71
72  def _ensure_sdk(self):
73    """Ensures the mac_toolchain tool and MacOS SDK packages are installed.
74
75    Returns Path to the installed sdk app bundle."""
76    cache_dir = self.m.path['cache'].join('macos_sdk')
77    pkgs = self.m.cipd.EnsureFile()
78    pkgs.add_package(self._tool_package, self._tool_version)
79    self.m.cipd.ensure(cache_dir, pkgs)
80
81    sdk_dir = cache_dir.join('XCode.app')
82    self.m.step('install xcode', [
83        cache_dir.join('mac_toolchain'),
84        'install',
85        '-kind',
86        'mac',
87        '-xcode-version',
88        self._sdk_version,
89        '-output-dir',
90        sdk_dir,
91    ])
92    return sdk_dir
93