From 3fa6c43bebbb01e75e56f782fc2b86d93c488d03 Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Thu, 25 Jan 2024 17:11:27 -0500 Subject: [PATCH] Remove the GitStatus plugin. (#189) A recent PR on Swift Package Manager (/~https://github.com/apple/swift-package-manager/pull/7202) added a `gitInformation` property to the package manifest's `Context` global. This property contains exactly the information we need from the GitStatus plugin. Let's remove it, then! Adopting the `gitInformation` property requires that we drop remaining support for Swift 5.10. We will continue to minimally support it in a separate Package.swift file (where we simply won't have git repo information at build time.) This PR does not strip out other 5.10 support code such as `XCTestScaffold`. Resolves rdar://121529847. --- Package.swift | 32 ++-- Package@swift-5.11.swift | 160 ++++++++++++++++++ Plugins/GitStatusPlugin/GitStatusPlugin.swift | 33 ---- Sources/GitStatus/main.swift | 120 ------------- Sources/Testing/Support/Versions.swift | 12 +- Sources/TestingInternals/include/Defines.h | 11 ++ 6 files changed, 187 insertions(+), 181 deletions(-) create mode 100644 Package@swift-5.11.swift delete mode 100644 Plugins/GitStatusPlugin/GitStatusPlugin.swift delete mode 100644 Sources/GitStatus/main.swift diff --git a/Package.swift b/Package.swift index 772a7bb62..3091c4b62 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.9 +// swift-tools-version: 5.10 // // This source file is part of the Swift.org open source project @@ -43,8 +43,8 @@ let package = Package( "TestingInternals", "TestingMacros", ], - swiftSettings: .packageSettings, - plugins: ["GitStatusPlugin"] + cxxSettings: .packageSettings, + swiftSettings: .packageSettings ), .testTarget( name: "TestingTests", @@ -79,20 +79,8 @@ let package = Package( // "Support" targets: These contain C family code and are used exclusively // by other targets above, not directly included in product libraries. .target( - name: "TestingInternals" - ), - - .plugin( - name: "GitStatusPlugin", - capability: .buildTool, - dependencies: ["GitStatus"] - ), - .executableTarget( - name: "GitStatus", - dependencies: [ - .product(name: "SwiftSyntax", package: "swift-syntax"), - .product(name: "SwiftSyntaxBuilder", package: "swift-syntax"), - ] + name: "TestingInternals", + cxxSettings: .packageSettings ), // Cross-module overlays (unsupported) @@ -148,3 +136,13 @@ extension Array where Element == PackageDescription.SwiftSetting { ] } } + +extension Array where Element == PackageDescription.CXXSetting { + /// Settings intended to be applied to every C++ target in this package. + /// Analogous to project-level build settings in an Xcode project. + static var packageSettings: Self { + [ + .define("_SWT_TESTING_LIBRARY_VERSION", to: #""unknown (Swift 5.10 toolchain)""#), + ] + } +} diff --git a/Package@swift-5.11.swift b/Package@swift-5.11.swift new file mode 100644 index 000000000..629d20393 --- /dev/null +++ b/Package@swift-5.11.swift @@ -0,0 +1,160 @@ +// swift-tools-version: 5.11 + +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2023 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for Swift project authors +// + +import PackageDescription +import CompilerPluginSupport + +let package = Package( + name: "swift-testing", + + platforms: [ + .macOS(.v10_15), + .iOS(.v13), + .watchOS(.v6), + .tvOS(.v13), + .macCatalyst(.v13), + .visionOS(.v1), + ], + + products: [ + .library( + name: "Testing", + targets: ["Testing"] + ), + ], + + dependencies: [ + .package(url: "/~https://github.com/apple/swift-syntax.git", from: "509.0.0"), + ], + + targets: [ + .target( + name: "Testing", + dependencies: [ + "TestingInternals", + "TestingMacros", + ], + cxxSettings: .packageSettings, + swiftSettings: .packageSettings + ), + .testTarget( + name: "TestingTests", + dependencies: [ + "Testing", + "_Testing_Foundation", + ], + swiftSettings: .packageSettings + ), + + .macro( + name: "TestingMacros", + dependencies: [ + .product(name: "SwiftDiagnostics", package: "swift-syntax"), + .product(name: "SwiftSyntax", package: "swift-syntax"), + .product(name: "SwiftSyntaxBuilder", package: "swift-syntax"), + .product(name: "SwiftParser", package: "swift-syntax"), + .product(name: "SwiftSyntaxMacros", package: "swift-syntax"), + .product(name: "SwiftCompilerPlugin", package: "swift-syntax"), + ], + swiftSettings: .packageSettings + [ + // The only target which needs the ability to import this macro + // implementation target's module is its unit test target. Users of the + // macros this target implements use them via their declarations in the + // Testing module. This target's module is never distributed to users, + // but as an additional guard against accidental misuse, this specifies + // the unit test target as the only allowable client. + .unsafeFlags(["-Xfrontend", "-allowable-client", "-Xfrontend", "TestingMacrosTests"]), + ] + ), + + // "Support" targets: These contain C family code and are used exclusively + // by other targets above, not directly included in product libraries. + .target( + name: "TestingInternals", + cxxSettings: .packageSettings + ), + + // Cross-module overlays (unsupported) + .target( + name: "_Testing_Foundation", + dependencies: [ + "Testing", + ], + swiftSettings: .packageSettings + ), + ], + + cxxLanguageStandard: .cxx20 +) + +// BUG: swift-package-manager-#6367 +#if !os(Windows) +package.targets.append(contentsOf: [ + .testTarget( + name: "TestingMacrosTests", + dependencies: [ + "Testing", + "TestingMacros", + ], + swiftSettings: .packageSettings + ) +]) +#endif + +extension Array where Element == PackageDescription.SwiftSetting { + /// Settings intended to be applied to every Swift target in this package. + /// Analogous to project-level build settings in an Xcode project. + static var packageSettings: Self { + [ + .unsafeFlags([ + "-require-explicit-sendable", + + "-Xfrontend", "-define-availability", "-Xfrontend", "_mangledTypeNameAPI:macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0", + "-Xfrontend", "-define-availability", "-Xfrontend", "_backtraceAsyncAPI:macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0", + "-Xfrontend", "-define-availability", "-Xfrontend", "_clockAPI:macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0", + "-Xfrontend", "-define-availability", "-Xfrontend", "_regexAPI:macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0", + "-Xfrontend", "-define-availability", "-Xfrontend", "_swiftVersionAPI:macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0", + + "-Xfrontend", "-define-availability", "-Xfrontend", "_distantFuture:macOS 99.0, iOS 99.0, watchOS 99.0, tvOS 99.0", + ]), + .enableExperimentalFeature("StrictConcurrency"), + .enableUpcomingFeature("ExistentialAny"), + + .enableExperimentalFeature("AccessLevelOnImport"), + .enableUpcomingFeature("InternalImportsByDefault"), + + .define("SWT_TARGET_OS_APPLE", .when(platforms: [.macOS, .iOS, .macCatalyst, .watchOS, .tvOS, .visionOS])), + ] + } +} + +extension Array where Element == PackageDescription.CXXSetting { + /// Settings intended to be applied to every C++ target in this package. + /// Analogous to project-level build settings in an Xcode project. + static var packageSettings: Self { + var result = Self() + + // Capture the testing library's version as a C++ string constant. + if let git = Context.gitInformation { + let testingLibraryVersion = if let tag = git.currentTag { + tag + } else if git.hasUncommittedChanges { + "\(git.currentCommit) (modified)" + } else { + git.currentCommit + } + result.append(.define("_SWT_TESTING_LIBRARY_VERSION", to: #""\#(testingLibraryVersion)""#)) + } + + return result + } +} diff --git a/Plugins/GitStatusPlugin/GitStatusPlugin.swift b/Plugins/GitStatusPlugin/GitStatusPlugin.swift deleted file mode 100644 index 78125ba54..000000000 --- a/Plugins/GitStatusPlugin/GitStatusPlugin.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2023 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for Swift project authors -// - -import PackagePlugin - -@main -struct GitStatus: BuildToolPlugin { - func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { -#if os(Windows) - /// BUG: Build plugins do not currently run on Windows. - /// swift-package-manager-#6851 - [] -#else - let repoPath = context.package.directory.string - let generatedSourcePath = context.pluginWorkDirectory.appending("TestingLibraryVersion.swift") - return [ - .buildCommand( - displayName: "Getting package repository state", - executable: try context.tool(named: "GitStatus").path, - arguments: [repoPath, generatedSourcePath], - outputFiles: [generatedSourcePath] - ), - ] -#endif - } -} diff --git a/Sources/GitStatus/main.swift b/Sources/GitStatus/main.swift deleted file mode 100644 index 58ab92fe7..000000000 --- a/Sources/GitStatus/main.swift +++ /dev/null @@ -1,120 +0,0 @@ -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2023 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for Swift project authors -// - -import SwiftSyntax -import SwiftSyntaxBuilder - -// FIXME: Instead of depending on Foundation, adopt API provided by SwiftPM in rdar://111523616 -// Note that SwiftPM already depends on Foundation, and this dependency does not -// introduce a dependency in the testing library, only in this helper tool. -import Foundation - -// Resolve arguments to the tool. -let repoPath = CommandLine.arguments[1] -let generatedSourceURL = URL(fileURLWithPath: CommandLine.arguments[2], isDirectory: false) - -/// Run the `git` tool and process the output it writes to standard output. -/// -/// - Parameters: -/// - arguments: The arguments to pass to `git`. -/// - maxOutputCount: The maximum amount of output to read and return. -/// -/// - Returns: A string containing the `git` command's output, up to -/// `maxOutputCount` UTF-8-encoded bytes, or `nil` if the command failed or -/// the output could not be read. -func _runGit(passing arguments: String..., readingUpToCount maxOutputCount: Int) -> String? { -#if os(macOS) || os(Linux) || os(Windows) - let path: String - let commonArguments = ["-C", repoPath] + arguments -#if os(Windows) - path = "C:\\Program Files\\Git\\cmd\\git.exe" - let arguments = commonArguments -#else - path = "/usr/bin/env" - let arguments = CollectionOfOne("git") + commonArguments -#endif - - let process = Process() - process.executableURL = URL(fileURLWithPath: path, isDirectory: false) - process.arguments = arguments - - let stdoutPipe = Pipe() - process.standardOutput = stdoutPipe - process.standardError = nil - do { - try process.run() - } catch { - return nil - } - defer { - process.terminate() - } - - let output = if #available(macOS 10.15.4, *) { - try? stdoutPipe.fileHandleForReading.read(upToCount: maxOutputCount) - } else { - stdoutPipe.fileHandleForReading.readData(ofLength: maxOutputCount) - } - return output.flatMap { String(data: $0, encoding: .utf8) } -#else - return nil -#endif -} - -// The current Git tag, if available. -let currentGitTag = _runGit(passing: "describe", "--exact-match", "--tags", readingUpToCount: 40)? - .split(whereSeparator: \.isNewline) - .first - .map(String.init) - -// The current Git commit hash, if available. -let currentGitCommitHash = _runGit(passing: "rev-parse", "HEAD", readingUpToCount: 40)? - .split(whereSeparator: \.isNewline) - .first - .map(String.init) - -// Whether or not the Git repository has uncommitted changes, if available. -let gitHasUncommittedChanges = _runGit(passing: "status", "-s", readingUpToCount: 1) - .map { !$0.isEmpty } ?? false - -// Figure out what value to emit for the testing library version. If the -// repository is sitting at a tag with no uncommitted changes, use the tag. -// Otherwise, use the commit hash (with a "there are changes" marker if needed.) -// Finally, fall back to nil if nothing else is available. -let sourceCode: DeclSyntax = if !gitHasUncommittedChanges, let currentGitTag { - """ - var _testingLibraryVersion: String? { - \(literal: currentGitTag) - } - """ -} else if let currentGitCommitHash { - if gitHasUncommittedChanges { - """ - var _testingLibraryVersion: String? { - \(literal: currentGitCommitHash) + " (modified)" - } - """ - } else { - """ - var _testingLibraryVersion: String? { - \(literal: currentGitCommitHash) - } - """ - } -} else { - """ - var _testingLibraryVersion: String? { - nil - } - """ -} - -// Write the generated Swift file to the specified destination path. -try String(describing: sourceCode).write(to: generatedSourceURL, atomically: false, encoding: .utf8) diff --git a/Sources/Testing/Support/Versions.swift b/Sources/Testing/Support/Versions.swift index 24ea6d8c4..a528278c9 100644 --- a/Sources/Testing/Support/Versions.swift +++ b/Sources/Testing/Support/Versions.swift @@ -120,18 +120,8 @@ let simulatorVersion: String = { /// ``XCTestScaffold`` or an event writer. /// /// This value is not part of the public interface of the testing library. -/// -/// - Bug: Build plugins do not currently run on Windows. -/// ([swift-package-manager-#6851](/~https://github.com/apple/swift-package-manager/issues/6851)) var testingLibraryVersion: String { -#if os(Windows) - "unknown" -#else - // The variable `_testingLibraryVersion` is generated at compile-time by the - // GitStatus plugin. If the plugin was unable to gather tag or commit - // information from Git, it produces a nil value. - _testingLibraryVersion ?? "unknown" -#endif + SWT_TESTING_LIBRARY_VERSION } /// A human-readable string describing the Swift Standard Library's version. diff --git a/Sources/TestingInternals/include/Defines.h b/Sources/TestingInternals/include/Defines.h index a93d3f8b2..5ff093472 100644 --- a/Sources/TestingInternals/include/Defines.h +++ b/Sources/TestingInternals/include/Defines.h @@ -32,4 +32,15 @@ /// An attribute that renames a C symbol in Swift. #define SWT_SWIFT_NAME(name) __attribute__((swift_name(#name))) +/// The testing library version from the package manifest. +/// +/// - Bug: The value provided to the compiler (`_SWT_TESTING_LIBRARY_VERSION`) +/// is not visible in Swift, so this second macro is needed. +/// ((#43521)[/~https://github.com/apple/swift/issues/43521]) +#if defined(_SWT_TESTING_LIBRARY_VERSION) +#define SWT_TESTING_LIBRARY_VERSION _SWT_TESTING_LIBRARY_VERSION +#else +#define SWT_TESTING_LIBRARY_VERSION "unknown" +#endif + #endif // SWT_DEFINES_H