mirror of
https://github.com/realm/SwiftLint.git
synced 2026-05-07 20:12:49 +00:00
Introduce guarded filepath provider for file collection (#6435)
This commit is contained in:
@@ -38,6 +38,7 @@ jobs:
|
||||
name: SPM, macOS ${{ matrix.macOS }}, Xcode ${{ matrix.xcode }}
|
||||
runs-on: macos-${{ matrix.macOS }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- macOS: '14'
|
||||
|
||||
+2
-2
@@ -39,7 +39,7 @@ default.profraw
|
||||
|
||||
SwiftLint.xcodeproj
|
||||
SwiftLint.pkg
|
||||
*.zip
|
||||
/*.zip
|
||||
benchmark_*
|
||||
docs/
|
||||
rule_docs/
|
||||
@@ -73,4 +73,4 @@ oss-check-summary.md
|
||||
|
||||
|
||||
# VS Code
|
||||
.vscode
|
||||
.vscode
|
||||
|
||||
@@ -20,6 +20,11 @@
|
||||
[SimplyDanny](https://github.com/SimplyDanny)
|
||||
[#6423](https://github.com/realm/SwiftLint/issues/6423)
|
||||
|
||||
* Inform users about files being skipped due to impossible file system representation
|
||||
instead of crashing.
|
||||
[SimplyDanny](https://github.com/SimplyDanny)
|
||||
[#6419](https://github.com/realm/SwiftLint/issues/6419)
|
||||
|
||||
* Ignore `override` functions in `async_without_await` rule.
|
||||
[SimplyDanny](https://github.com/SimplyDanny)
|
||||
[#6416](https://github.com/realm/SwiftLint/issues/6416)
|
||||
|
||||
@@ -203,6 +203,7 @@ let package = Package(
|
||||
.testTarget(
|
||||
name: "IntegrationTests",
|
||||
dependencies: [
|
||||
"SwiftLintCore",
|
||||
"SwiftLintFramework",
|
||||
"TestHelpers",
|
||||
],
|
||||
|
||||
@@ -5,6 +5,18 @@ public extension URL {
|
||||
withUnsafeFileSystemRepresentation { String(cString: $0!) }
|
||||
}
|
||||
|
||||
var filepathGuarded: String? {
|
||||
withUnsafeFileSystemRepresentation { ptr in
|
||||
guard let ptr else {
|
||||
Issue.genericError(
|
||||
"File with URL '\(self)' cannot be represented as a file system path; skipping it"
|
||||
).print()
|
||||
return nil
|
||||
}
|
||||
return String(cString: ptr)
|
||||
}
|
||||
}
|
||||
|
||||
var isSwiftFile: Bool {
|
||||
filepath.isFile && pathExtension == "swift"
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ extension FileManager: LintableFileManager, @unchecked @retroactive Sendable {
|
||||
}
|
||||
|
||||
private func collectFiles(atPath absolutePath: URL, excluder: Excluder) -> [String] {
|
||||
guard let enumerator = enumerator(atPath: absolutePath.filepath) else {
|
||||
guard let root = absolutePath.filepathGuarded, let enumerator = enumerator(atPath: root) else {
|
||||
return []
|
||||
}
|
||||
|
||||
@@ -80,7 +80,9 @@ extension FileManager: LintableFileManager, @unchecked @retroactive Sendable {
|
||||
|
||||
while let element = enumerator.nextObject() as? String {
|
||||
let absoluteElementPath = URL(fileURLWithPath: element, relativeTo: absolutePath)
|
||||
let absoluteStandardizedElementPath = absoluteElementPath.standardized.filepath
|
||||
guard let absoluteStandardizedElementPath = absoluteElementPath.standardized.filepathGuarded else {
|
||||
continue
|
||||
}
|
||||
if absoluteElementPath.path.isFile {
|
||||
if absoluteElementPath.pathExtension == "swift",
|
||||
!excluder.excludes(path: absoluteStandardizedElementPath) {
|
||||
|
||||
@@ -3,7 +3,9 @@ import SwiftLintFramework
|
||||
import TestHelpers
|
||||
import XCTest
|
||||
|
||||
final class ConfigPathResolutionTests: SwiftLintTestCase {
|
||||
@testable import SwiftLintCore
|
||||
|
||||
final class ConfigPathResolutionTests: SwiftLintTestCase, @unchecked Sendable {
|
||||
private func fixturePath(_ scenario: String) -> URL {
|
||||
URL(fileURLWithPath: #filePath)
|
||||
.deletingLastPathComponent()
|
||||
@@ -16,10 +18,8 @@ final class ConfigPathResolutionTests: SwiftLintTestCase {
|
||||
let scenarioPath = fixturePath(scenario).filepath
|
||||
|
||||
let previousDir = FileManager.default.currentDirectoryPath
|
||||
defer {
|
||||
_ = FileManager.default.changeCurrentDirectoryPath(previousDir)
|
||||
}
|
||||
XCTAssert(FileManager.default.changeCurrentDirectoryPath(scenarioPath))
|
||||
defer { _ = FileManager.default.changeCurrentDirectoryPath(previousDir) }
|
||||
|
||||
let config = Configuration(configurationFiles: configFile.map { [$0] } ?? [])
|
||||
let files = config.lintableFiles(
|
||||
@@ -169,4 +169,36 @@ final class ConfigPathResolutionTests: SwiftLintTestCase {
|
||||
.contains("explicit_type_interface")
|
||||
)
|
||||
}
|
||||
|
||||
#if !os(Windows)
|
||||
func testUnicodePrivateUseAreaCharacterInPath() async throws {
|
||||
let fixture = fixturePath("_8_unicode_private_use_area")
|
||||
|
||||
let process = Process()
|
||||
process.executableURL = URL(filePath: "/usr/bin/env", directoryHint: .notDirectory)
|
||||
process.arguments = ["unzip", "-o", fixture.appending(path: "app.zip").filepath, "-d", fixture.filepath]
|
||||
try process.run()
|
||||
process.waitUntilExit()
|
||||
defer { try? FileManager.default.removeItem(at: fixture.appending(path: "App")) }
|
||||
|
||||
if #available(macOS 26, *) {
|
||||
XCTAssertEqual(
|
||||
lintableFilePaths(in: "_8_unicode_private_use_area/App"),
|
||||
["Resources/Settings.bundle/androidx.core:core-bundle.swift"]
|
||||
)
|
||||
} else {
|
||||
let console = await Issue.captureConsole {
|
||||
XCTAssert(lintableFilePaths(in: "_8_unicode_private_use_area/App").isEmpty)
|
||||
}
|
||||
XCTAssert(
|
||||
console.contains(
|
||||
"""
|
||||
error: File with URL 'androidx.core:core-bundle.swift' \
|
||||
cannot be represented as a file system path; skipping it
|
||||
"""
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user