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