Fix Xcode 11.3.1 detection in an Xcode workspace When using a Tulsi-generated project by itself in Xcode 11.3.1, Xcode sets XCODE_VERSION_ACTUAL to 1131, which Tulsi parses correctly to get the version 11.3.1. But when used in an Xcode workspace, Xcode sets XCODE_VERSION_ACTUAL to 1130, leading to Tulsi parsing 11.3 as the version, and later attempts to use a non-existing version of Xcode to build, which results in an error. Fix by ignoring XCODE_VERSION_ACTUAL because it's unreliable; instead, parse Xcode's version.plist to read the 'CFBundleShortVersionString' entry, which seems to return correct results. Caveat: this implementation uses plistlib, which has a slightly different API in python2 and python3. This change uses the python2 API, and will need to be updated to work with python3 in the future. PiperOrigin-RevId: 315886285
diff --git a/src/TulsiGenerator/Scripts/bazel_build.py b/src/TulsiGenerator/Scripts/bazel_build.py index f741b50..0723f7e 100755 --- a/src/TulsiGenerator/Scripts/bazel_build.py +++ b/src/TulsiGenerator/Scripts/bazel_build.py
@@ -25,6 +25,7 @@ import json import os import pipes +import plistlib import re import shutil import signal @@ -340,17 +341,39 @@ @staticmethod def _GetXcodeVersionString(): - """Returns Xcode version info from the environment as a string.""" - reported_version = os.environ['XCODE_VERSION_ACTUAL'] - match = re.match(r'(\d{2})(\d)(\d)$', reported_version) - if not match: - _PrintUnbuffered('Warning: Failed to extract Xcode version from %s' % ( - reported_version)) + """Returns Xcode version info from the Xcode's version.plist. + + Just reading XCODE_VERSION_ACTUAL from the environment seems like + a more reasonable implementation, but has shown to be unreliable, + at least when using Xcode 11.3.1 and opening the project within an + Xcode workspace. + """ + developer_dir = os.environ['DEVELOPER_DIR'] + app_dir = developer_dir.split('.app')[0] + '.app' + version_plist_path = os.path.join(app_dir, 'Contents', 'version.plist') + try: + # python2 API to plistlib - needs updating if/when Tulsi bumps to python3 + plist = plistlib.readPlist(version_plist_path) + except IOError: + _PrintXcodeWarning('Tulsi cannot determine Xcode version, error ' + 'reading from {}'.format(version_plist_path)) return None - major_version = int(match.group(1)) - minor_version = int(match.group(2)) - fix_version = int(match.group(3)) - return '%d.%d.%d' % (major_version, minor_version, fix_version) + try: + # Example: "11.3.1", "11.3", "11.0" + key = 'CFBundleShortVersionString' + version_string = plist[key] + except KeyError: + _PrintXcodeWarning('Tulsi cannot determine Xcode version from {}, no ' + '"{}" key'.format(version_plist_path, key)) + return None + + # But we need to normalize to major.minor.patch, e.g. 11.3.0 or + # 11.0.0, so add one or two ".0" if needed (two just in case + # there is ever just a single version number like "12") + dots_count = version_string.count('.') + dot_zeroes_to_add = 2 - dots_count + version_string += '.0' * dot_zeroes_to_add + return version_string @staticmethod def _ComputeXcodeVersionFlag():