From 8b81990bc2c59f117714bdca65d36b70ac035f46 Mon Sep 17 00:00:00 2001 From: tom doron Date: Fri, 5 Feb 2021 10:48:16 -0800 Subject: [PATCH 1/2] move Versionig back to SwiftPM motivation: the logic in Versioning does not belong in TSC, its a SwiftPM concern changes: * move Versioning/SwiftVersion to Basics module * move Git::convertTagsToVersionMap to its only callsite * adjust callsites --- Sources/Basics/HTTPClient.swift | 2 +- Sources/Basics/SwiftVersion.swift | 75 +++++++++++++++++++ Sources/Commands/SwiftBuildTool.swift | 9 ++- .../SwiftPackageCollectionsTool.swift | 3 +- Sources/Commands/SwiftPackageTool.swift | 2 +- Sources/Commands/SwiftRunTool.swift | 7 +- Sources/Commands/SwiftTestTool.swift | 2 +- .../RepositoryPackageContainer.swift | 45 +++++++++++ Sources/PackageLoading/ManifestLoader.swift | 2 +- .../PackageLoading/ToolsVersionLoader.swift | 7 +- Sources/PackageModel/ToolsVersion.swift | 12 +-- .../VersionSpecificTests.swift | 11 ++- .../ManifestLoaderSQLiteCacheTests.swift | 3 +- .../PD4_2LoadingTests.swift | 12 +-- .../ToolsVersionLoaderTests.swift | 10 +-- 15 files changed, 163 insertions(+), 39 deletions(-) create mode 100644 Sources/Basics/SwiftVersion.swift diff --git a/Sources/Basics/HTTPClient.swift b/Sources/Basics/HTTPClient.swift index 0cb6cb5ef08..d11d6e2bd82 100644 --- a/Sources/Basics/HTTPClient.swift +++ b/Sources/Basics/HTTPClient.swift @@ -79,7 +79,7 @@ public struct HTTPClient: HTTPClientProtocol { } } if request.options.addUserAgent, !request.headers.contains("User-Agent") { - request.headers.add(name: "User-Agent", value: "SwiftPackageManager/\(Versioning.currentVersion.displayString)") + request.headers.add(name: "User-Agent", value: "SwiftPackageManager/\(SwiftVersion.currentVersion.displayString)") } // execute self._execute(request: request, requestNumber: 0) { result in diff --git a/Sources/Basics/SwiftVersion.swift b/Sources/Basics/SwiftVersion.swift new file mode 100644 index 00000000000..399d3451839 --- /dev/null +++ b/Sources/Basics/SwiftVersion.swift @@ -0,0 +1,75 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See http://swift.org/LICENSE.txt for license information + See http://swift.org/CONTRIBUTORS.txt for Swift project authors + */ + +@_implementationOnly import TSCclibc + +public struct SwiftVersion { + /// The version number. + public var version: (major: Int, minor: Int, patch: Int) + + /// Whether or not this is a development version. + public var isDevelopment: Bool + + /// Build information, as an unstructured string. + public var buildIdentifier: String? + + /// The major component of the version number. + public var major: Int { return version.major } + /// The minor component of the version number. + public var minor: Int { return version.minor } + /// The patch component of the version number. + public var patch: Int { return version.patch } + + /// The version as a readable string. + public var displayString: String { + var result = "\(major).\(minor).\(patch)" + if isDevelopment { + result += "-dev" + } + if let buildIdentifier = self.buildIdentifier { + result += " (" + buildIdentifier + ")" + } + return result + } + + /// The complete product version display string (including the name). + public var completeDisplayString: String { + var vendorPrefix = String(cString: SPM_VendorNameString()) + if !vendorPrefix.isEmpty { + vendorPrefix += " " + } + return vendorPrefix + "Swift Package Manager - Swift " + displayString + } + + /// The list of version specific identifiers to search when attempting to + /// load version specific package or version information, in order of + /// preference. + public var versionSpecificKeys: [String] { + return [ + "@swift-\(major).\(minor).\(patch)", + "@swift-\(major).\(minor)", + "@swift-\(major)", + ] + } + +} + +extension SwiftVersion { + /// The current version of the package manager. + public static let currentVersion = SwiftVersion( + version: (5, 4, 0), + isDevelopment: true, + buildIdentifier: getBuildIdentifier()) +} + +private func getBuildIdentifier() -> String? { + let buildIdentifier = String(cString: SPM_BuildIdentifierString()) + return buildIdentifier.isEmpty ? nil : buildIdentifier +} diff --git a/Sources/Commands/SwiftBuildTool.swift b/Sources/Commands/SwiftBuildTool.swift index 2a9d4742992..94bed850854 100644 --- a/Sources/Commands/SwiftBuildTool.swift +++ b/Sources/Commands/SwiftBuildTool.swift @@ -9,11 +9,12 @@ */ import ArgumentParser -import TSCUtility -import TSCBasic +import Basics +import Build import PackageGraph import SPMBuildCore -import Build +import TSCBasic +import TSCUtility extension BuildSubset { var argumentName: String { @@ -79,7 +80,7 @@ public struct SwiftBuildTool: SwiftCommand { _superCommandName: "swift", abstract: "Build sources into binary products", discussion: "SEE ALSO: swift run, swift package, swift test", - version: Versioning.currentVersion.completeDisplayString, + version: SwiftVersion.currentVersion.completeDisplayString, helpNames: [.short, .long, .customLong("help", withSingleDash: true)]) @OptionGroup() diff --git a/Sources/Commands/SwiftPackageCollectionsTool.swift b/Sources/Commands/SwiftPackageCollectionsTool.swift index 6f6aa95c69b..01787030db3 100644 --- a/Sources/Commands/SwiftPackageCollectionsTool.swift +++ b/Sources/Commands/SwiftPackageCollectionsTool.swift @@ -9,6 +9,7 @@ */ import ArgumentParser +import Basics import Foundation import PackageCollections import PackageModel @@ -42,7 +43,7 @@ public struct SwiftPackageCollectionsTool: ParsableCommand { _superCommandName: "swift", abstract: "Interact with package collections", discussion: "SEE ALSO: swift build, swift package, swift run, swift test", - version: Versioning.currentVersion.completeDisplayString, + version: SwiftVersion.currentVersion.completeDisplayString, subcommands: [ Add.self, Describe.self, diff --git a/Sources/Commands/SwiftPackageTool.swift b/Sources/Commands/SwiftPackageTool.swift index 78e1dad1121..9c1f4f461c3 100644 --- a/Sources/Commands/SwiftPackageTool.swift +++ b/Sources/Commands/SwiftPackageTool.swift @@ -30,7 +30,7 @@ public struct SwiftPackageTool: ParsableCommand { _superCommandName: "swift", abstract: "Perform operations on Swift packages", discussion: "SEE ALSO: swift build, swift run, swift test", - version: Versioning.currentVersion.completeDisplayString, + version: SwiftVersion.currentVersion.completeDisplayString, subcommands: [ Clean.self, PurgeCache.self, diff --git a/Sources/Commands/SwiftRunTool.swift b/Sources/Commands/SwiftRunTool.swift index d95576083b4..e161e4e73b3 100644 --- a/Sources/Commands/SwiftRunTool.swift +++ b/Sources/Commands/SwiftRunTool.swift @@ -9,11 +9,12 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ import ArgumentParser -import TSCBasic +import Basics import Build -import TSCUtility import PackageGraph import PackageModel +import TSCBasic +import TSCUtility /// An enumeration of the errors that can be generated by the run tool. private enum RunError: Swift.Error { @@ -86,7 +87,7 @@ public struct SwiftRunTool: SwiftCommand { _superCommandName: "swift", abstract: "Build and run an executable product", discussion: "SEE ALSO: swift build, swift package, swift test", - version: Versioning.currentVersion.completeDisplayString, + version: SwiftVersion.currentVersion.completeDisplayString, helpNames: [.short, .long, .customLong("help", withSingleDash: true)]) @OptionGroup() diff --git a/Sources/Commands/SwiftTestTool.swift b/Sources/Commands/SwiftTestTool.swift index 2f0a117a94f..93552f5f678 100644 --- a/Sources/Commands/SwiftTestTool.swift +++ b/Sources/Commands/SwiftTestTool.swift @@ -191,7 +191,7 @@ public struct SwiftTestTool: SwiftCommand { _superCommandName: "swift", abstract: "Build and run tests", discussion: "SEE ALSO: swift build, swift run, swift package", - version: Versioning.currentVersion.completeDisplayString, + version: SwiftVersion.currentVersion.completeDisplayString, helpNames: [.short, .long, .customLong("help", withSingleDash: true)]) @OptionGroup() diff --git a/Sources/PackageGraph/RepositoryPackageContainer.swift b/Sources/PackageGraph/RepositoryPackageContainer.swift index 96a91e66c23..52bda16fec1 100644 --- a/Sources/PackageGraph/RepositoryPackageContainer.swift +++ b/Sources/PackageGraph/RepositoryPackageContainer.swift @@ -384,3 +384,48 @@ public class RepositoryPackageContainerProvider: PackageContainerProvider { } } } + +extension Git { + static func convertTagsToVersionMap(_ tags: [String]) -> [Version: [String]] { + // First, check if we need to restrict the tag set to version-specific tags. + var knownVersions: [Version: [String]] = [:] + var versionSpecificKnownVersions: [Version: [String]] = [:] + + for tag in tags { + for versionSpecificKey in SwiftVersion.currentVersion.versionSpecificKeys { + if tag.hasSuffix(versionSpecificKey) { + let trimmedTag = String(tag.dropLast(versionSpecificKey.count)) + if let version = Version(tag: trimmedTag) { + versionSpecificKnownVersions[version, default: []].append(tag) + } + break + } + } + + if let version = Version(tag: tag) { + knownVersions[version, default: []].append(tag) + } + } + // Check if any version specific tags were found. + // If true, then return the version specific tags, + // or else return the version independent tags. + if !versionSpecificKnownVersions.isEmpty { + return versionSpecificKnownVersions + } else { + return knownVersions + } + } +} + +extension Version { + /// Try a version from a git tag. + /// + /// - Parameter tag: A version string possibly prepended with "v". + init?(tag: String) { + if tag.first == "v" { + self.init(string: String(tag.dropFirst())) + } else { + self.init(string: tag) + } + } +} diff --git a/Sources/PackageLoading/ManifestLoader.swift b/Sources/PackageLoading/ManifestLoader.swift index b71cdda6c1b..0300acd19d8 100644 --- a/Sources/PackageLoading/ManifestLoader.swift +++ b/Sources/PackageLoading/ManifestLoader.swift @@ -556,7 +556,7 @@ public final class ManifestLoader: ManifestLoaderProtocol { manifestPath: path, toolsVersion: toolsVersion, env: ProcessEnv.vars, - swiftpmVersion: Versioning.currentVersion.displayString, + swiftpmVersion: SwiftVersion.currentVersion.displayString, fileSystem: fileSystem ) diff --git a/Sources/PackageLoading/ToolsVersionLoader.swift b/Sources/PackageLoading/ToolsVersionLoader.swift index aa31ad0dbb1..49fdf816b09 100644 --- a/Sources/PackageLoading/ToolsVersionLoader.swift +++ b/Sources/PackageLoading/ToolsVersionLoader.swift @@ -8,10 +8,11 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ -import TSCBasic +import Basics +import Foundation import PackageModel +import TSCBasic import TSCUtility -import Foundation /// Protocol for the manifest loader interface. public protocol ToolsVersionLoaderProtocol { @@ -37,7 +38,7 @@ extension Manifest { fileSystem: FileSystem ) throws -> AbsolutePath { // Look for a version-specific manifest. - for versionSpecificKey in Versioning.currentVersionSpecificKeys { + for versionSpecificKey in SwiftVersion.currentVersion.versionSpecificKeys { let versionSpecificPath = packagePath.appending(component: Manifest.basename + versionSpecificKey + ".swift") if fileSystem.isFile(versionSpecificPath) { return versionSpecificPath diff --git a/Sources/PackageModel/ToolsVersion.swift b/Sources/PackageModel/ToolsVersion.swift index 27329159070..c39cd02f0db 100644 --- a/Sources/PackageModel/ToolsVersion.swift +++ b/Sources/PackageModel/ToolsVersion.swift @@ -8,9 +8,9 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ -import TSCBasic - +import Basics import Foundation +import TSCBasic import TSCUtility /// Tools version represents version of the Swift toolchain. @@ -27,9 +27,9 @@ public struct ToolsVersion: Equatable, Hashable, Codable { /// The current tools version in use. public static let currentToolsVersion = ToolsVersion(string: - "\(Versioning.currentVersion.major)." + - "\(Versioning.currentVersion.minor)." + - "\(Versioning.currentVersion.patch)")! + "\(SwiftVersion.currentVersion.major)." + + "\(SwiftVersion.currentVersion.minor)." + + "\(SwiftVersion.currentVersion.patch)")! /// The minimum tools version that is required by the package manager. public static let minimumRequired: ToolsVersion = .v4 @@ -106,7 +106,7 @@ public struct ToolsVersion: Equatable, Hashable, Codable { packagePath: String ) throws { // We don't want to throw any error when using the special vNext version. - if Versioning.currentVersion.isDevelopment && self == .vNext { + if SwiftVersion.currentVersion.isDevelopment && self == .vNext { return } diff --git a/Tests/FunctionalTests/VersionSpecificTests.swift b/Tests/FunctionalTests/VersionSpecificTests.swift index 27bca27ff2f..56ec1187dc5 100644 --- a/Tests/FunctionalTests/VersionSpecificTests.swift +++ b/Tests/FunctionalTests/VersionSpecificTests.swift @@ -8,13 +8,12 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ -import XCTest - -import TSCBasic +import Basics import SourceControl -import TSCUtility - import SPMTestSupport +import TSCBasic +import TSCUtility +import XCTest class VersionSpecificTests: XCTestCase { /// Functional tests of end-to-end support for version specific dependency resolution. @@ -112,7 +111,7 @@ class VersionSpecificTests: XCTestCase { } try repo.stage(file: "Package.swift") try repo.commit(message: "OK v1.1.0") - try repo.tag(name: "1.1.0@swift-\(Versioning.currentVersion.major)") + try repo.tag(name: "1.1.0@swift-\(SwiftVersion.currentVersion.major)") // The build should work now. _ = try SwiftPMProduct.SwiftPackage.execute(["reset"], packagePath: primaryPath) diff --git a/Tests/PackageLoadingTests/ManifestLoaderSQLiteCacheTests.swift b/Tests/PackageLoadingTests/ManifestLoaderSQLiteCacheTests.swift index adfb98e60d8..3d19cd8bc03 100644 --- a/Tests/PackageLoadingTests/ManifestLoaderSQLiteCacheTests.swift +++ b/Tests/PackageLoadingTests/ManifestLoaderSQLiteCacheTests.swift @@ -8,6 +8,7 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ +import Basics @testable import PackageLoading import PackageModel import TSCBasic @@ -186,7 +187,7 @@ fileprivate func makeMockManifests(fileSystem: FileSystem, rootPath: AbsolutePat manifestPath: manifestPath, toolsVersion: ToolsVersion.currentToolsVersion, env: [:], - swiftpmVersion: Versioning.currentVersion.displayString, + swiftpmVersion: SwiftVersion.currentVersion.displayString, fileSystem: fileSystem) manifests[key] = ManifestLoader.ManifestParseResult(compilerOutput: "mock-output-\(index)", parsedManifest: "{ 'name': 'mock-manifest-\(index)' }") diff --git a/Tests/PackageLoadingTests/PD4_2LoadingTests.swift b/Tests/PackageLoadingTests/PD4_2LoadingTests.swift index d6bf52e93ed..569aa354ef2 100644 --- a/Tests/PackageLoadingTests/PD4_2LoadingTests.swift +++ b/Tests/PackageLoadingTests/PD4_2LoadingTests.swift @@ -8,13 +8,13 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ -import XCTest - -import TSCBasic -import TSCUtility -import SPMTestSupport +import Basics import PackageModel import PackageLoading +import SPMTestSupport +import TSCBasic +import TSCUtility +import XCTest class PackageDescription4_2LoadingTests: PackageDescriptionLoadingTests { override var toolsVersion: ToolsVersion { @@ -327,7 +327,7 @@ class PackageDescription4_2LoadingTests: PackageDescriptionLoadingTests { "let package = Package(name: \"Trivial\")")) // Check at each possible spelling. - let currentVersion = Versioning.currentVersion + let currentVersion = SwiftVersion.currentVersion let possibleSuffixes = [ "\(currentVersion.major).\(currentVersion.minor).\(currentVersion.patch)", "\(currentVersion.major).\(currentVersion.minor)", diff --git a/Tests/PackageLoadingTests/ToolsVersionLoaderTests.swift b/Tests/PackageLoadingTests/ToolsVersionLoaderTests.swift index 92c92982a1a..f4c18dd7d6b 100644 --- a/Tests/PackageLoadingTests/ToolsVersionLoaderTests.swift +++ b/Tests/PackageLoadingTests/ToolsVersionLoaderTests.swift @@ -8,14 +8,14 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ -import XCTest - -import TSCBasic -import SPMTestSupport +import Basics import PackageModel import PackageLoading +import SPMTestSupport +import TSCBasic import TSCUtility +import XCTest class ToolsVersionLoaderTests: XCTestCase { @@ -674,7 +674,7 @@ class ToolsVersionLoaderTests: XCTestCase { } // Test version specific manifests. - let keys = Versioning.currentVersionSpecificKeys + let keys = SwiftVersion.currentVersion.versionSpecificKeys // In case the count ever changes, we will need to modify this test. XCTAssertEqual(keys.count, 3) From 1c0f4642ff71f84ae5993415b5c21a20a97b1db6 Mon Sep 17 00:00:00 2001 From: tom doron Date: Fri, 5 Feb 2021 11:32:20 -0800 Subject: [PATCH 2/2] cmake --- Sources/Basics/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sources/Basics/CMakeLists.txt b/Sources/Basics/CMakeLists.txt index 103189b2825..d87f672c725 100644 --- a/Sources/Basics/CMakeLists.txt +++ b/Sources/Basics/CMakeLists.txt @@ -15,10 +15,13 @@ add_library(Basics FileSystem+Extensions.swift HTPClient+URLSession.swift HTTPClient.swift - JSON+Extensions.swift) + JSON+Extensions.swift + SwiftVersion.swift) target_link_libraries(Basics PUBLIC TSCBasic TSCUtility) +target_link_libraries(Basics PRIVATE + TSCclibc) # NOTE(compnerd) workaround for CMake not setting up include flags yet set_target_properties(Basics PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})