Automated rollback of commit f0bab83186b9e474ce2c7fda0e93be838086b3c0. *** Reason for rollback *** Rollforward with fixes to include a default swift version fetched via xcrun *** Original change description *** Automated rollback of commit 59704429b54110ed10a7490704cbbdee2232b0c9. *** Reason for rollback *** Breaks Swift test generation as we no longer have a default swift version; we will need to use xcrun to come up with a default. *** Original change description *** Use swift provider to fetch swift version PiperOrigin-RevId: 185891775
diff --git a/src/TulsiGenerator/Base.lproj/Localizable.strings b/src/TulsiGenerator/Base.lproj/Localizable.strings index 2260b3f..f1f18d3 100644 --- a/src/TulsiGenerator/Base.lproj/Localizable.strings +++ b/src/TulsiGenerator/Base.lproj/Localizable.strings
@@ -65,6 +65,9 @@ /* Message to show when the execution root was not able to be extracted from the workspace. */ "ExecutionRootNotFound" = "Was not able to extract the execution root from the workspace. This is a Tulsi or Bazel bug, please report."; +/* Message to show when unable to extract the default swift version from xcrun. */ +"ExtractingDefaultSwiftVersionFailed" = "Unable to extract default swift version from xcrun. Defaulting to swift version %1$@. Additional error context: %2$@."; + /* Failed to readString from FileLineReader when handling the BEP file. */ "FileLineReaderReadStringFailed" = "Failed to readString from the BEP JSON file. This is a Tulsi or Bazel bug, please report.";
diff --git a/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl b/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl index 1c30818..47a5a6c 100644 --- a/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl +++ b/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl
@@ -466,14 +466,6 @@ return str(min_os) -def _extract_swift_language_version(ctx): - """Returns the Swift version of a swift_library rule.""" - - if ctx.rule.kind != 'swift_library': - return None - return _get_label_attr(ctx, 'rule.attr.swift_version') or "3.0" - - def _collect_swift_modules(target): """Returns a depset of Swift modules found on the given target.""" swift_modules = depset() @@ -633,9 +625,9 @@ infoplist = None # Build up any local transitive attributes and apply them. - swift_language_version = _extract_swift_language_version(ctx) - if swift_language_version: - transitive_attributes['swift_language_version'] = swift_language_version + swift = _get_opt_attr(target, 'swift') + if swift: + transitive_attributes['swift_language_version'] = getattr(swift, 'swift_version', None) transitive_attributes['has_swift_dependency'] = True all_attributes = attributes + inheritable_attributes + transitive_attributes
diff --git a/src/TulsiGenerator/XcodeProjectGenerator.swift b/src/TulsiGenerator/XcodeProjectGenerator.swift index af3e332..319465c 100644 --- a/src/TulsiGenerator/XcodeProjectGenerator.swift +++ b/src/TulsiGenerator/XcodeProjectGenerator.swift
@@ -77,6 +77,7 @@ private static let StubWatchOS2InfoPlistFilename = "StubWatchOS2InfoPlist.plist" private static let StubWatchOS2AppExInfoPlistFilename = "StubWatchOS2AppExInfoPlist.plist" private static let CachedExecutionRootFilename = "execroot_path.py" + private static let DefaultSwiftVersion = "4" /// Rules which should not be generated at the top level. private static let LibraryRulesForTopLevelWarning = @@ -113,6 +114,8 @@ /// generated by Bazel. var suppressGeneratedArtifactFolderCreation = false + var cachedDefaultSwiftVersion: String? + init(workspaceRootURL: URL, config: TulsiGeneratorConfig, localizedMessageLogger: LocalizedMessageLogger, @@ -231,6 +234,74 @@ // MARK: - Private methods + /// Extracts the default swift version to use for targets without an explicit default by running + /// 'xcrun swift --version' if not already fetched. + private func fetchDefaultSwitchVersion() -> String { + // Used the already computed default version if it is available. + if let defaultSwiftVersion = cachedDefaultSwiftVersion { + return defaultSwiftVersion + } + + let semaphore = DispatchSemaphore(value: 0) + var completionInfo: ProcessRunner.CompletionInfo? + let process = TulsiProcessRunner.createProcess("/usr/bin/xcrun", + arguments: ["swift", "--version"], + messageLogger: self.localizedMessageLogger, + loggingIdentifier: "extract_default_swift_version") { + processCompletionInfo in + defer { semaphore.signal() } + + completionInfo = processCompletionInfo + } + process.launch() + _ = semaphore.wait(timeout: DispatchTime.distantFuture) + + guard let info = completionInfo else { + self.localizedMessageLogger.warning("ExtractingDefaultSwiftVersionFailed", + comment: "Default version in %1$@, additional error context in %2$@.", + values: XcodeProjectGenerator.DefaultSwiftVersion, + "Internal error, unable to find process information") + cachedDefaultSwiftVersion = XcodeProjectGenerator.DefaultSwiftVersion + return XcodeProjectGenerator.DefaultSwiftVersion + } + + guard info.terminationStatus == 0, + let stdout = NSString(data: info.stdout, encoding: String.Encoding.utf8.rawValue) else { + let stderr = NSString(data: info.stderr, encoding: String.Encoding.utf8.rawValue) ?? "<no stderr>" + self.localizedMessageLogger.warning("ExtractingDefaultSwiftVersionFailed", + comment: "Default version in %1$@, additional error context in %2$@.", + values: XcodeProjectGenerator.DefaultSwiftVersion, + "xcrun swift --version returned exitcode \(info.terminationStatus) with stderr: \(stderr)") + cachedDefaultSwiftVersion = XcodeProjectGenerator.DefaultSwiftVersion + return XcodeProjectGenerator.DefaultSwiftVersion + } + // Example output format: + // Apple Swift version 4.0.3 (swiftlang-900.0.74.1 clang-900.0.39.2) + // Target: x86_64-apple-macosx10.9 + // + // Note that we only care about the major and minor version number (e.g. 4.0, not 4.0.3). + let pattern = "^Apple\\sSwift\\sversion\\s([0-9]+\\.?[0-9]?)" + guard let regExpr = try? NSRegularExpression(pattern: pattern, options: .caseInsensitive) else { + self.localizedMessageLogger.warning("ExtractingDefaultSwiftVersionFailed", + comment: "Default version in %1$@, additional error context in %2$@.", + values: XcodeProjectGenerator.DefaultSwiftVersion, + "Internal error, unable to create regular expression") + cachedDefaultSwiftVersion = XcodeProjectGenerator.DefaultSwiftVersion + return XcodeProjectGenerator.DefaultSwiftVersion + } + guard let match = regExpr.firstMatch(in: stdout as String, + range: NSMakeRange(0, stdout.length)) else { + self.localizedMessageLogger.warning("ExtractingDefaultSwiftVersionFailed", + comment: "Default version in %1$@, additional error context in %2$@.", + values: XcodeProjectGenerator.DefaultSwiftVersion, + "Unable to parse version from xcrun output. Output: \(stdout)") + cachedDefaultSwiftVersion = XcodeProjectGenerator.DefaultSwiftVersion + return XcodeProjectGenerator.DefaultSwiftVersion + } + cachedDefaultSwiftVersion = stdout.substring(with: match.rangeAt(1)) + return stdout.substring(with: match.rangeAt(1)) + } + /// Encapsulates information about the results of a buildXcodeProjectWithMainGroup invocation. private struct GeneratedProjectInfo { /// The newly created PBXProject instance. @@ -419,6 +490,8 @@ for entry in targetRules { if let swiftVersion = entry.attributes[.swift_language_version] as? String { buildSettings["SWIFT_VERSION"] = swiftVersion + } else if entry.attributes[.has_swift_dependency] as? Bool ?? false { + buildSettings["SWIFT_VERSION"] = fetchDefaultSwitchVersion() } if let swiftToolchain = entry.attributes[.swift_toolchain] as? String { buildSettings["TOOLCHAINS"] = swiftToolchain