From 1c38d02ae8270428a9f84381e6f6ff284115ee72 Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 22 May 2023 19:43:50 +0800 Subject: [PATCH] Migrate code to use Swift Regex --- Sources/Build/BuildOperation.swift | 3 +-- ...dOperationBuildSystemDelegateHandler.swift | 13 ++++----- .../GitHubPackageMetadataProvider.swift | 18 +++---------- .../PackageLoading/ToolsVersionParser.swift | 27 ++++++++++++------- .../PackageModel/SwiftLanguageVersion.swift | 26 +++++++++++------- .../PackageRegistryTool+Publish.swift | 4 +-- .../SourceControlPackageContainer.swift | 6 ++--- 7 files changed, 49 insertions(+), 48 deletions(-) diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index c16df3aa956..4a2e945a1cd 100644 --- a/Sources/Build/BuildOperation.swift +++ b/Sources/Build/BuildOperation.swift @@ -23,7 +23,6 @@ import class TSCBasic.DiagnosticsEngine import protocol TSCBasic.OutputByteStream import class TSCBasic.Process import enum TSCBasic.ProcessEnv -import struct TSCBasic.RegEx import enum TSCUtility.Diagnostics import class TSCUtility.MultiLineNinjaProgressAnimation @@ -690,7 +689,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS guard let _ = self._buildPlan?.targets.first(where: { $0.target.name == target }) else { return nil } // Check for cases involving modules that cannot be found. - if let importedModule = try? RegEx(pattern: "no such module '(.+)'").matchGroups(in: message).first?.first { + if let importedModule = message.firstMatch(of: #/no such module '(?.+)'/#)?.module { // A target is importing a module that can't be found. We take a look at the build plan and see if can offer any advice. // Look for a target with the same module name as the one that's being imported. diff --git a/Sources/Build/BuildOperationBuildSystemDelegateHandler.swift b/Sources/Build/BuildOperationBuildSystemDelegateHandler.swift index 482235fe985..6fbfc249fae 100644 --- a/Sources/Build/BuildOperationBuildSystemDelegateHandler.swift +++ b/Sources/Build/BuildOperationBuildSystemDelegateHandler.swift @@ -23,7 +23,6 @@ import struct TSCBasic.Format import class TSCBasic.LocalFileOutputByteStream import protocol TSCBasic.OutputByteStream import enum TSCBasic.ProcessEnv -import struct TSCBasic.RegEx import class TSCBasic.ThreadSafeOutputByteStream import class TSCUtility.IndexStore @@ -933,11 +932,13 @@ final class BuildOperationBuildSystemDelegateHandler: LLBuildBuildSystemDelegate // next we want to try and scoop out any errors from the output (if reasonable size, otherwise this // will be very slow), so they can later be passed to the advice provider in case of failure. if output.utf8.count < 1024 * 10 { - let regex = try! RegEx(pattern: #".*(error:[^\n]*)\n.*"#, options: .dotMatchesLineSeparators) - for match in regex.matchGroups(in: output) { - self.errorMessagesByTarget[parser.targetName] = ( - self.errorMessagesByTarget[parser.targetName] ?? [] - ) + [match[0]] + let regex = #/.*(?error:[^\n]*)\n.*/#.dotMatchesNewlines() + for match in output.matches(of: regex) { + self + .errorMessagesByTarget[parser.targetName] = ( + self + .errorMessagesByTarget[parser.targetName] ?? [] + ) + [String(match.error)] } } } diff --git a/Sources/PackageCollections/Providers/GitHubPackageMetadataProvider.swift b/Sources/PackageCollections/Providers/GitHubPackageMetadataProvider.swift index ad32f77b2e2..f5604ea676b 100644 --- a/Sources/PackageCollections/Providers/GitHubPackageMetadataProvider.swift +++ b/Sources/PackageCollections/Providers/GitHubPackageMetadataProvider.swift @@ -252,23 +252,11 @@ struct GitHubPackageMetadataProvider: PackageMetadataProvider, Closable { // FIXME: use URL instead of string internal static func apiURL(_ url: String) -> URL? { - do { - let regex = try NSRegularExpression(pattern: #"([^/@]+)[:/]([^:/]+)/([^/.]+)(\.git)?$"#, options: .caseInsensitive) - if let match = regex.firstMatch(in: url, options: [], range: NSRange(location: 0, length: url.count)) { - if let hostRange = Range(match.range(at: 1), in: url), - let ownerRange = Range(match.range(at: 2), in: url), - let repoRange = Range(match.range(at: 3), in: url) { - let host = String(url[hostRange]) - let owner = String(url[ownerRange]) - let repo = String(url[repoRange]) - - return URL(string: "https://\(Self.apiHostPrefix)\(host)/repos/\(owner)/\(repo)") - } - } - return nil - } catch { + let regex = #/(?[^/@]+)[:/](?[^:/]+)/(?[^/.]+)(\.git)?$/#.ignoresCase() + guard let match = url.firstMatch(of: regex) else { return nil } + return URL(string: "https://\(Self.apiHostPrefix)\(match.host)/repos/\(match.owner)/\(match.repo)") } private func makeRequestOptions(validResponseCodes: [Int]) -> LegacyHTTPClientRequest.Options { diff --git a/Sources/PackageLoading/ToolsVersionParser.swift b/Sources/PackageLoading/ToolsVersionParser.swift index b5b010f2472..db42d3b7c4f 100644 --- a/Sources/PackageLoading/ToolsVersionParser.swift +++ b/Sources/PackageLoading/ToolsVersionParser.swift @@ -15,7 +15,6 @@ import Foundation import PackageModel import struct TSCBasic.ByteString -import struct TSCBasic.RegEx import struct TSCUtility.Version @@ -621,19 +620,27 @@ extension ManifestLoader { do { contents = try fileSystem.getDirectoryContents(packagePath) } catch { throw ToolsVersionParser.Error.inaccessiblePackage(path: packagePath, reason: String(describing: error)) } - let regex = try! RegEx(pattern: #"^Package@swift-(\d+)(?:\.(\d+))?(?:\.(\d+))?.swift$"#) - + let regex = #/^Package@swift-(?\d+)(?:\.(?\d+))?(?:\.(?\d+))?.swift$/# // Collect all version-specific manifests at the given package path. let versionSpecificManifests = Dictionary(contents.compactMap{ file -> (ToolsVersion, String)? in - let parsedVersion = regex.matchGroups(in: file) - guard parsedVersion.count == 1, parsedVersion[0].count == 3 else { + let parsedVersionMatches = file.matches(of: regex) + guard parsedVersionMatches.count == 1, + let parsedVersion = parsedVersionMatches.first else { return nil } - - let major = Int(parsedVersion[0][0])! - let minor = parsedVersion[0][1].isEmpty ? 0 : Int(parsedVersion[0][1])! - let patch = parsedVersion[0][2].isEmpty ? 0 : Int(parsedVersion[0][2])! - + let major = Int(parsedVersion.major) ?? 0 + let minor: Int + if let minorString = parsedVersion.minor { + minor = Int(minorString) ?? 0 + } else { + minor = 0 + } + let patch: Int + if let patchString = parsedVersion.patch { + patch = Int(patchString) ?? 0 + } else { + patch = 0 + } return (ToolsVersion(version: Version(major, minor, patch)), file) }, uniquingKeysWith: { $1 }) diff --git a/Sources/PackageModel/SwiftLanguageVersion.swift b/Sources/PackageModel/SwiftLanguageVersion.swift index 2aabc03c138..d62be7ab7fb 100644 --- a/Sources/PackageModel/SwiftLanguageVersion.swift +++ b/Sources/PackageModel/SwiftLanguageVersion.swift @@ -12,8 +12,6 @@ import Foundation -import struct TSCBasic.RegEx - import struct TSCUtility.Version /// Represents a Swift language version. @@ -60,21 +58,31 @@ public struct SwiftLanguageVersion: Hashable, Sendable { } /// Regex for parsing the Swift language version. - private static let regex = try! RegEx(pattern: #"^(\d+)(?:\.(\d+))?(?:\.(\d+))?$"#) + private static let regex = #/^(?\d+)(?:\.(?\d+))?(?:\.(?\d+))?$/# /// Create an instance of Swift language version from the given string. /// // The Swift language version is not officially fixed but we require it to // be a valid SemVer-like string. public init?(string: String) { - let parsedVersion = SwiftLanguageVersion.regex.matchGroups(in: string) - guard parsedVersion.count == 1, parsedVersion[0].count == 3 else { + let parsedVersions = string.matches(of: SwiftLanguageVersion.regex) + guard parsedVersions.count == 1 else { return nil } - let major = Int(parsedVersion[0][0])! - let minor = parsedVersion[0][1].isEmpty ? 0 : Int(parsedVersion[0][1])! - let patch = parsedVersion[0][2].isEmpty ? 0 : Int(parsedVersion[0][2])! - + let parsedVersion = parsedVersions[0] + let major = Int(parsedVersion.major) ?? 0 + let minor: Int + if let minorString = parsedVersion.minor { + minor = Int(minorString) ?? 0 + } else { + minor = 0 + } + let patch: Int + if let patchString = parsedVersion.patch { + patch = Int(patchString) ?? 0 + } else { + patch = 0 + } self.rawValue = string self._version = Version(major, minor, patch) } diff --git a/Sources/PackageRegistryTool/PackageRegistryTool+Publish.swift b/Sources/PackageRegistryTool/PackageRegistryTool+Publish.swift index d049340aff7..5cab928f92a 100644 --- a/Sources/PackageRegistryTool/PackageRegistryTool+Publish.swift +++ b/Sources/PackageRegistryTool/PackageRegistryTool+Publish.swift @@ -433,9 +433,9 @@ enum PackageArchiveSigner { } manifests.append(Manifest.filename) - let regex = try RegEx(pattern: #"^Package@swift-(\d+)(?:\.(\d+))?(?:\.(\d+))?.swift$"#) + let regex = #/^Package@swift-(\d+)(?:\.(\d+))?(?:\.(\d+))?.swift$/# let versionSpecificManifests: [String] = packageContents.filter { file in - let matchGroups = regex.matchGroups(in: file) + let matchGroups = file.matches(of: regex) return !matchGroups.isEmpty } manifests.append(contentsOf: versionSpecificManifests) diff --git a/Sources/Workspace/PackageContainer/SourceControlPackageContainer.swift b/Sources/Workspace/PackageContainer/SourceControlPackageContainer.swift index 6e634df9fd4..d8df9238850 100644 --- a/Sources/Workspace/PackageContainer/SourceControlPackageContainer.swift +++ b/Sources/Workspace/PackageContainer/SourceControlPackageContainer.swift @@ -19,8 +19,6 @@ import PackageLoading import PackageModel import SourceControl -import struct TSCBasic.RegEx - import enum TSCUtility.Git import struct TSCUtility.Version @@ -287,8 +285,8 @@ internal final class SourceControlPackageContainer: PackageContainer, CustomStri ) } else { // Revision does not exist, so we customize the error. - let sha1RegEx = try! RegEx(pattern: #"\A[:xdigit:]{40}\Z"#) - let isBranchRev = sha1RegEx.matchGroups(in: revision).compactMap { $0 }.isEmpty + let sha1RegEx = #/\A[:xdigit:]{40}\Z/# + let isBranchRev = revision.matches(of: sha1RegEx).isEmpty let errorMessage = "could not find " + (isBranchRev ? "a branch named ‘\(revision)’" : "the commit \(revision)") let mainBranchExists = (try? repository.resolveRevision(identifier: "main")) != nil let suggestion = (revision == "master" && mainBranchExists) ? "did you mean ‘main’?" : nil