Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate code to use Swift Regex #6598

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Sources/Build/BuildOperation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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>.+)'/#)?.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.
Expand Down
13 changes: 7 additions & 6 deletions Sources/Build/BuildOperationBuildSystemDelegateHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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>error:[^\n]*)\n.*/#.dotMatchesNewlines()
for match in output.matches(of: regex) {
self
.errorMessagesByTarget[parser.targetName] = (
self
.errorMessagesByTarget[parser.targetName] ?? []
) + [String(match.error)]
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = #/(?<host>[^/@]+)[:/](?<owner>[^:/]+)/(?<repo>[^/.]+)(\.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 {
Expand Down
27 changes: 17 additions & 10 deletions Sources/PackageLoading/ToolsVersionParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import Foundation
import PackageModel

import struct TSCBasic.ByteString
import struct TSCBasic.RegEx

import struct TSCUtility.Version

Expand Down Expand Up @@ -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-(?<major>\d+)(?:\.(?<minor>\d+))?(?:\.(?<patch>\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 })

Expand Down
26 changes: 17 additions & 9 deletions Sources/PackageModel/SwiftLanguageVersion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@

import Foundation

import struct TSCBasic.RegEx

import struct TSCUtility.Version

/// Represents a Swift language version.
Expand Down Expand Up @@ -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 = #/^(?<major>\d+)(?:\.(?<minor>\d+))?(?:\.(?<patch>\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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ import PackageLoading
import PackageModel
import SourceControl

import struct TSCBasic.RegEx

import enum TSCUtility.Git
import struct TSCUtility.Version

Expand Down Expand Up @@ -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
Expand Down