1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# Copyright 2014 The Chromium Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7import argparse
8import doctest
9import itertools
10import os
11import subprocess
12import sys
13
14# This script prints information about the build system, the operating
15# system and the iOS or Mac SDK (depending on the platform "iphonesimulator",
16# "iphoneos" or "macosx" generally).
17
18
19def split_version(version: str or bytes):
20    """
21    Splits the Xcode version to 3 values.
22
23    >>> list(split_version('8.2.1.1'))
24    ['8', '2', '1']
25    >>> list(split_version('9.3'))
26    ['9', '3', '0']
27    >>> list(split_version('10.0'))
28    ['10', '0', '0']
29    """
30    if isinstance(version, bytes):
31        version = version.decode()
32    version = version.split('.')
33    return itertools.islice(itertools.chain(version, itertools.repeat('0')), 0, 3)
34
35
36def format_version(version: str or bytes):
37    """
38    Converts Xcode version to a format required for DTXcode in Info.plist
39
40    >>> format_version('8.2.1')
41    '0821'
42    >>> format_version('9.3')
43    '0930'
44    >>> format_version('10.0')
45    '1000'
46    """
47    major, minor, patch = split_version(version)
48    return ('%2s%s%s' % (major, minor, patch)).replace(' ', '0')
49
50
51def fill_xcode_version(fill_settings: dict) -> dict:
52    """Fills the Xcode version and build number into |fill_settings|."""
53
54    try:
55        lines = subprocess.check_output(['xcodebuild', '-version']).splitlines()
56        fill_settings['xcode_version'] = format_version(lines[0].split()[-1])
57        fill_settings['xcode_version_int'] = int(fill_settings['xcode_version'], 10)
58        fill_settings['xcode_build'] = lines[-1].split()[-1]
59    except subprocess.CalledProcessError as cpe:
60        print(f"Failed to run xcodebuild -version: {cpe}")
61
62
63def fill_machine_os_build(fill_settings: dict):
64    """Fills OS build number into |fill_settings|."""
65    fill_settings['machine_os_build'] = subprocess.check_output(
66        ['sw_vers', '-buildVersion']).strip()
67
68
69def fill_sdk_path_and_version(fill_settings: dict, platform: str, xcode_version: str or bytes):
70    """Fills the SDK path and version for |platform| into |fill_settings|."""
71    fill_settings['sdk_path'] = subprocess.check_output([
72        'xcrun', '-sdk', platform, '--show-sdk-path']).strip()
73    fill_settings['sdk_version'] = subprocess.check_output([
74        'xcrun', '-sdk', platform, '--show-sdk-version']).strip()
75    fill_settings['sdk_platform_path'] = subprocess.check_output([
76        'xcrun', '-sdk', platform, '--show-sdk-platform-path']).strip()
77    if xcode_version >= '0720':
78        fill_settings['sdk_build'] = subprocess.check_output([
79          'xcrun', '-sdk', platform, '--show-sdk-build-version']).strip()
80    else:
81        fill_settings['sdk_build'] = fill_settings['sdk_version']
82
83
84if __name__ == '__main__':
85    doctest.testmod()
86
87    parser = argparse.ArgumentParser()
88    parser.add_argument("--developer_dir", required=False)
89    args, unknownargs = parser.parse_known_args()
90    if args.developer_dir:
91        os.environ['DEVELOPER_DIR'] = args.developer_dir
92
93    if len(unknownargs) != 1:
94        sys.stderr.write(
95          'usage: %s [iphoneos|iphonesimulator|macosx]\n' %
96          os.path.basename(sys.argv[0]))
97        sys.exit(1)
98
99    settings = {}
100    fill_machine_os_build(settings)
101    fill_xcode_version(settings)
102    try:
103        fill_sdk_path_and_version(settings, unknownargs[0], settings.get('xcode_version'))
104    except ValueError as vle:
105        print(f"Error: {vle}")
106
107    for key in sorted(settings):
108        value = settings.get(key)
109        if isinstance(value, bytes):
110            value = value.decode()
111        if key != 'xcode_version_int':
112            value = '"%s"' % value
113            print('%s=%s' % (key, value))
114        else:
115            print('%s=%d' % (key, value))
116