Correct incorrect handling of file paths (#6355)

`URL.path` is not a usable rendering of the path. `URL.path` represents
the URI path. If the path is meant to be consumable as a file path, the
file system representation (aka FSR) must be retrieved.

This improves the file path handling and makes additional tests now
pass.

Co-authored-by: Danny Mösch <danny.moesch@icloud.com>
This commit is contained in:
Saleem Abdulrasool
2025-12-01 13:02:12 -08:00
committed by GitHub
parent 15b1930763
commit 562ec8f369
6 changed files with 31 additions and 21 deletions
@@ -70,7 +70,7 @@ public extension String {
///
/// - returns: A new `String`.
func absolutePathStandardized() -> String {
bridge().absolutePathRepresentation().bridge().standardizingPath
URL(fileURLWithPath: bridge().standardizingPath.absolutePathRepresentation()).filepath
}
var isFile: Bool {
@@ -0,0 +1,11 @@
import Foundation
public extension URL {
var filepath: String {
self.withUnsafeFileSystemRepresentation { String(cString: $0!) }
}
var isSwiftFile: Bool {
filepath.isFile && pathExtension == "swift"
}
}
@@ -31,19 +31,18 @@ public protocol LintableFileManager {
extension FileManager: LintableFileManager {
public func filesToLint(inPath path: String, rootDirectory: String? = nil) -> [String] {
let absolutePath = path.bridge()
.absolutePathRepresentation(rootDirectory: rootDirectory ?? currentDirectoryPath).bridge()
.standardizingPath
let root =
URL(fileURLWithPath: path.absolutePathRepresentation(rootDirectory: rootDirectory ?? currentDirectoryPath))
// if path is a file, it won't be returned in `enumerator(atPath:)`
if absolutePath.bridge().isSwiftFile(), absolutePath.isFile {
return [absolutePath]
}
if root.isSwiftFile { return [root.standardized.filepath] }
return subpaths(atPath: absolutePath)?.parallelCompactMap { element -> String? in
guard element.bridge().isSwiftFile() else { return nil }
let absoluteElementPath = absolutePath.bridge().appendingPathComponent(element)
return absoluteElementPath.isFile ? absoluteElementPath : nil
return subpaths(atPath: root.path)?.parallelCompactMap { element -> String? in
let elementURL = URL(fileURLWithPath: element, relativeTo: root)
if elementURL.isSwiftFile {
return elementURL.standardized.filepath
}
return nil
} ?? []
}
+8 -8
View File
@@ -49,26 +49,26 @@ extension SwiftLintDev.Rules {
.appendingPathComponent("SwiftLintBuiltInRules", isDirectory: true)
.appendingPathComponent("Rules", isDirectory: true)
let ruleLocation = ruleDirectory.appendingPathComponent(kind.rawValue.capitalized, isDirectory: true)
guard FileManager.default.fileExists(atPath: ruleLocation.path) else {
guard FileManager.default.fileExists(atPath: ruleLocation.filepath) else {
throw ValidationError("Command must be run from the root of the SwiftLint repository.")
}
print("Creating template(s) for new rule \"\(ruleName)\" identified by '\(ruleId)' ...")
let rulePath = ruleLocation.appendingPathComponent("\(name)Rule.swift", isDirectory: false)
guard overwrite || !FileManager.default.fileExists(atPath: rulePath.path) else {
guard overwrite || !FileManager.default.fileExists(atPath: rulePath.filepath) else {
throw ValidationError("Rule file already exists at \(rulePath.relativeToCurrentDirectory).")
}
try ruleTemplate.write(toFile: rulePath.path, atomically: true, encoding: .utf8)
try ruleTemplate.write(toFile: rulePath.filepath, atomically: true, encoding: .utf8)
print("Rule file created at \(rulePath.relativeToCurrentDirectory).")
if config {
let configPath = ruleDirectory
.appendingPathComponent("RuleConfigurations", isDirectory: true)
.appendingPathComponent("\(name)Configuration.swift", isDirectory: false)
guard overwrite || !FileManager.default.fileExists(atPath: configPath.path) else {
guard overwrite || !FileManager.default.fileExists(atPath: configPath.filepath) else {
throw ValidationError(
"Configuration file already exists at \(configPath.relativeToCurrentDirectory)."
)
}
try configTemplate.write(toFile: configPath.path, atomically: true, encoding: .utf8)
try configTemplate.write(toFile: configPath.filepath, atomically: true, encoding: .utf8)
print("Configuration file created at \(configPath.relativeToCurrentDirectory).")
}
if test {
@@ -76,13 +76,13 @@ extension SwiftLintDev.Rules {
.appendingPathComponent("Tests", isDirectory: true)
.appendingPathComponent("BuiltInRulesTests", isDirectory: true)
let testPath = testDirectory.appendingPathComponent("\(name)RuleTests.swift", isDirectory: false)
guard FileManager.default.fileExists(atPath: testDirectory.path) else {
guard FileManager.default.fileExists(atPath: testDirectory.filepath) else {
throw ValidationError("Command must be run from the root of the SwiftLint repository.")
}
guard overwrite || !FileManager.default.fileExists(atPath: testPath.path) else {
guard overwrite || !FileManager.default.fileExists(atPath: testPath.filepath) else {
throw ValidationError("Test file already exists at \(testPath.relativeToCurrentDirectory).")
}
try testTemplate.write(toFile: testPath.path, atomically: true, encoding: .utf8)
try testTemplate.write(toFile: testPath.filepath, atomically: true, encoding: .utf8)
print("Test file created at \(testPath.relativeToCurrentDirectory).")
}
if !skipRegistration {
@@ -8,7 +8,7 @@ private var temporaryDirectoryPath: String {
let result = URL(
fileURLWithPath: NSTemporaryDirectory(),
isDirectory: true
).path
).filepath
#if os(macOS)
return "/private" + result
+1 -1
View File
@@ -95,7 +95,7 @@ private extension SwiftLintFile {
public extension String {
func stringByAppendingPathComponent(_ pathComponent: String) -> String {
bridge().appendingPathComponent(pathComponent)
URL(fileURLWithPath: self).appendingPathComponent(pathComponent).filepath
}
}