Require macOS 12 & Swift 5.6 (#4037)

This will unblock using Swift Concurrency features and updating to the
latest versions of Swift Argument Parser.

This won't drop support for linting projects with an older toolchain /
Xcode selected, as long as SwiftLint was _built_ with 5.6+ and is
_running_ on macOS 12+. So the main breaking change for end users here
is requiring macOS 12 to run.

However, the upside to using Swift Concurrency features is worth the
breaking change in my opinion. Also being able to stay on recent Swift
Argument Parser releases.
This commit is contained in:
JP Simard 2022-07-26 03:55:36 -04:00 committed by GitHub
parent 09837b7bab
commit 05ac3c9d75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 56 additions and 116 deletions

View File

@ -27,6 +27,14 @@ macOS < 12.
positional paths that can be added last to both commands.
[SimplyDanny](https://github.com/SimplyDanny)
* SwiftLint now requires Swift 5.6 or higher to build, and macOS 12
or higher to run.
[JP Simard](https://github.com/jpsim)
* Code Climate reports now use SHA256 strings as the issue fingerprint
values.
[JP Simard](https://github.com/jpsim)
#### Experimental
* None.

View File

@ -15,8 +15,8 @@
"repositoryURL": "https://github.com/apple/swift-argument-parser.git",
"state": {
"branch": null,
"revision": "e394bf350e38cb100b6bc4172834770ede1b7232",
"version": "1.0.3"
"revision": "df9ee6676cd5b3bf5b330ec7568a5644f547201b",
"version": "1.1.3"
}
},
{

View File

@ -9,36 +9,29 @@ private let addCryptoSwift = true
private let staticSwiftSyntax = false
#endif
#if os(Linux) && compiler(<5.6)
private let swiftSyntaxFiveDotSix = false
#else
private let swiftSyntaxFiveDotSix = true
#endif
let frameworkDependencies: [Target.Dependency] = [
.product(name: "SourceKittenFramework", package: "SourceKitten"),
.product(name: "SwiftSyntax", package: "SwiftSyntax"),
.product(name: "SwiftSyntaxParser", package: "SwiftSyntax"),
"Yams",
]
+ (addCryptoSwift ? ["CryptoSwift"] : [])
+ (staticSwiftSyntax ? ["lib_InternalSwiftSyntaxParser"] : [])
+ (swiftSyntaxFiveDotSix ? [.product(name: "SwiftSyntaxParser", package: "SwiftSyntax")] : [])
let package = Package(
name: "SwiftLint",
platforms: [.macOS(.v10_12)],
platforms: [.macOS(.v12)],
products: [
.executable(name: "swiftlint", targets: ["swiftlint"]),
.library(name: "SwiftLintFramework", targets: ["SwiftLintFramework"])
],
dependencies: [
.package(name: "swift-argument-parser", url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.0.3")),
.package(name: "SwiftSyntax", url: "https://github.com/apple/swift-syntax.git",
.exact(swiftSyntaxFiveDotSix ? "0.50600.1" : "0.50500.0")),
.package(name: "swift-argument-parser", url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.1.3")),
.package(name: "SwiftSyntax", url: "https://github.com/apple/swift-syntax.git", .exact("0.50600.1")),
.package(url: "https://github.com/jpsim/SourceKitten.git", from: "0.32.0"),
.package(url: "https://github.com/jpsim/Yams.git", from: "4.0.2"),
.package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"),
] + (addCryptoSwift ? [.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.4.3"))] : []),
] + (addCryptoSwift ? [.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.5.1"))] : []),
targets: [
.executableTarget(
name: "swiftlint",
@ -51,7 +44,6 @@ let package = Package(
.target(
name: "SwiftLintFramework",
dependencies: frameworkDependencies,
swiftSettings: swiftSyntaxFiveDotSix ? [.define("SWIFT_SYNTAX_FIVE_DOT_SIX")] : [],
// Pass `-dead_strip_dylibs` to ignore the dynamic version of `lib_InternalSwiftSyntaxParser`
// that ships with SwiftSyntax because we want the static version from
// `StaticInternalSwiftSyntaxParser`.

View File

@ -60,7 +60,7 @@ running it.
### Installing from source:
You can also build and install from source by cloning this project and running
`make install` (Xcode 13 or later).
`make install` (Xcode 13.3 or later).
## Usage

View File

@ -65,7 +65,7 @@ extension Configuration {
let jsonObject: [Any] = [rootDirectory, cacheRulesDescriptions]
if let jsonData = try? JSONSerialization.data(withJSONObject: jsonObject),
let jsonString = String(data: jsonData, encoding: .utf8) {
return jsonString.md5()
return jsonString.sha256()
}
queuedFatalError("Could not serialize configuration for cache")
}

View File

@ -1,15 +0,0 @@
#if canImport(CommonCrypto)
import CommonCrypto
extension String {
internal func md5() -> String {
let context = UnsafeMutablePointer<CC_MD5_CTX>.allocate(capacity: 1)
var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
CC_MD5_Init(context)
CC_MD5_Update(context, self, CC_LONG(lengthOfBytes(using: .utf8)))
CC_MD5_Final(&digest, context)
context.deallocate()
return digest.reduce(into: "") { $0.append(String(format: "%02x", $1)) }
}
}
#endif

View File

@ -0,0 +1,14 @@
#if canImport(CommonCrypto)
import CommonCrypto
extension String {
internal func sha256() -> String {
let theData = data(using: .utf8)!
return theData.withUnsafeBytes { bytes in
var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
_ = CC_SHA256(bytes.baseAddress, CC_LONG(theData.count), &hash)
return hash.reduce(into: "") { $0.append(String(format: "%02x", $1)) }
}
}
}
#endif

View File

@ -1,33 +1,4 @@
import Foundation
import SourceKittenFramework
#if os(Linux)
private extension Scanner {
func scanString(string: String) -> String? {
return scanString(string)
}
}
#else
private extension Scanner {
func scanUpToString(_ string: String) -> String? {
var result: NSString?
let success = scanUpTo(string, into: &result)
if success {
return result?.bridge()
}
return nil
}
func scanString(string: String) -> String? {
var result: NSString?
let success = scanString(string, into: &result)
if success {
return result?.bridge()
}
return nil
}
}
#endif
/// A SwiftLint-interpretable command to modify SwiftLint's behavior embedded as comments in source code.
public struct Command: Equatable {
@ -100,7 +71,7 @@ public struct Command: Equatable {
/// defined.
public init?(actionString: String, line: Int, character: Int) {
let scanner = Scanner(string: actionString)
_ = scanner.scanString(string: "swiftlint:")
_ = scanner.scanString("swiftlint:")
// (enable|disable)(:previous|:this|:next)
guard let actionAndModifierString = scanner.scanUpToString(" ") else {
return nil
@ -120,9 +91,12 @@ public struct Command: Equatable {
trailingComment = nil
} else {
// Store any text after the comment delimiter as the trailingComment.
// The addition to scanLocation is to move past the delimiter
let startOfCommentPastDelimiter = scanner.scanLocation + Self.commentDelimiter.count
trailingComment = scanner.string.bridge().substring(from: startOfCommentPastDelimiter)
// The addition to currentIndex is to move past the delimiter
trailingComment = String(
scanner
.string[scanner.currentIndex...]
.dropFirst(Self.commentDelimiter.count)
)
}
let ruleTexts = rawRuleTexts.components(separatedBy: .whitespacesAndNewlines).filter {
let component = $0.trimmingCharacters(in: .whitespaces)
@ -132,11 +106,13 @@ public struct Command: Equatable {
ruleIdentifiers = Set(ruleTexts.map(RuleIdentifier.init(_:)))
// Modifier
let hasModifier = actionAndModifierScanner.scanString(string: ":") != nil
let hasModifier = actionAndModifierScanner.scanString(":") != nil
if hasModifier {
let modifierString = actionAndModifierScanner.string.bridge()
.substring(from: actionAndModifierScanner.scanLocation)
modifier = Modifier(rawValue: modifierString)
modifier = Modifier(
rawValue: String(
actionAndModifierScanner.string[actionAndModifierScanner.currentIndex...]
)
)
} else {
modifier = nil
}

View File

@ -50,6 +50,6 @@ public struct CodeClimateReporter: Reporter {
return [
"\(fingerprintLocation)",
"\(violation.ruleIdentifier)"
].joined().md5()
].joined().sha256()
}
}

View File

@ -90,10 +90,8 @@ public struct UnavailableConditionRule: ConfigurationProviderRule, AutomaticTest
switch check {
case is AvailabilityConditionSyntax:
return "Use #unavailable instead of #available with an empty body."
#if SWIFT_SYNTAX_FIVE_DOT_SIX
case is UnavailabilityConditionSyntax:
return "Use #available instead of #unavailable with an empty body."
#endif
default:
queuedFatalError("Unknown availability check type.")
}
@ -123,12 +121,8 @@ private final class UnavailableConditionRuleVisitor: SyntaxVisitor {
}
private func asAvailabilityCondition(_ condition: Syntax) -> SyntaxProtocol? {
let availability = condition.as(AvailabilityConditionSyntax.self)
#if SWIFT_SYNTAX_FIVE_DOT_SIX
return availability ?? condition.as(UnavailabilityConditionSyntax.self)
#else
return availability
#endif
condition.as(AvailabilityConditionSyntax.self) ??
condition.as(UnavailabilityConditionSyntax.self)
}
private func otherAvailabilityCheckInvolved(ifStmt: IfStmtSyntax) -> Bool {

View File

@ -1,5 +1,4 @@
import Foundation
import SourceKittenFramework
struct CompilerArgumentsExtractor {
static func allCompilerInvocations(compilerLogs: String) -> [[String]] {
@ -18,28 +17,6 @@ struct CompilerArgumentsExtractor {
// MARK: - Private
#if !os(Linux)
private extension Scanner {
func scanUpToString(_ string: String) -> String? {
var result: NSString?
let success = scanUpTo(string, into: &result)
if success {
return result?.bridge()
}
return nil
}
func scanString(_ string: String) -> String? {
var result: NSString?
let success = scanString(string, into: &result)
if success {
return result?.bridge()
}
return nil
}
}
#endif
private func parseCLIArguments(_ string: String) -> [String] {
let escapedSpacePlaceholder = "\u{0}"
let scanner = Scanner(string: string)

View File

@ -47,7 +47,7 @@ struct LintOrAnalyzeArguments: ParsableArguments {
// `LintOrAnalyzeArguments`.
func pathOptionDescription(for mode: LintOrAnalyzeMode) -> ArgumentHelp {
ArgumentHelp(shouldDisplay: false)
ArgumentHelp(visibility: .hidden)
}
func pathsArgumentDescription(for mode: LintOrAnalyzeMode) -> ArgumentHelp {

View File

@ -3,7 +3,7 @@
"check_name" : "Line Length",
"description" : "Violation Reason.",
"engine_name" : "SwiftLint",
"fingerprint" : "091a80392f7aebde05dab908162c3629",
"fingerprint" : "917a85854a9500cfd28520fa4875a3ecbba171e522f13452c7adec71fc14497a",
"location" : {
"lines" : {
"begin" : 1,
@ -18,7 +18,7 @@
"check_name" : "Line Length",
"description" : "Violation Reason.",
"engine_name" : "SwiftLint",
"fingerprint" : "091a80392f7aebde05dab908162c3629",
"fingerprint" : "917a85854a9500cfd28520fa4875a3ecbba171e522f13452c7adec71fc14497a",
"location" : {
"lines" : {
"begin" : 1,
@ -33,7 +33,7 @@
"check_name" : "Syntactic Sugar",
"description" : "Shorthand syntactic sugar should be used, i.e. [Int] instead of Array<Int>.",
"engine_name" : "SwiftLint",
"fingerprint" : "624a4e77e797c9e6a42c82b6428e9c45",
"fingerprint" : "6477f518963149b01807a31e7067be97dc39a30b93673e1e246f812e9ea5ef21",
"location" : {
"lines" : {
"begin" : 1,
@ -48,7 +48,7 @@
"check_name" : "Colon Spacing",
"description" : "Colons should be next to the identifier when specifying a type and next to the key in dictionary literals.",
"engine_name" : "SwiftLint",
"fingerprint" : "1f9389145aa6d7e89a582fce5ae54659",
"fingerprint" : "9b1ddedc847d23a54124cb02a56452fc01c23df8f3babc07a6a68cf2449b14a6",
"location" : {
"lines" : {
"begin" : null,

View File

@ -8,8 +8,6 @@ jobs:
strategy:
maxParallel: 10
matrix:
swift55:
containerImage: swift:5.5
swift56:
containerImage: swift:5.6
container: $[ variables['containerImage'] ]
@ -23,8 +21,6 @@ jobs:
strategy:
maxParallel: 10
matrix:
xcode1321:
DEVELOPER_DIR: /Applications/Xcode_13.2.1.app
xcode1331:
DEVELOPER_DIR: /Applications/Xcode_13.3.1.app
steps:
@ -41,8 +37,6 @@ jobs:
strategy:
maxParallel: 10
matrix:
xcode1321:
DEVELOPER_DIR: /Applications/Xcode_13.2.1.app
xcode1331:
DEVELOPER_DIR: /Applications/Xcode_13.3.1.app
steps: