Skip to content

Commit

Permalink
Migrate code to use Swift Regex
Browse files Browse the repository at this point in the history
  • Loading branch information
Kyle-Ye committed Feb 5, 2024
1 parent 5b1fe44 commit ec95df5
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 48 deletions.
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
4 changes: 2 additions & 2 deletions Sources/PackageRegistryTool/PackageRegistryTool+Publish.swift
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

0 comments on commit ec95df5

Please sign in to comment.