Skip to content

Commit c60a236

Browse files
KaiOelfkefortmarek
andauthored
feat: handle relative symbolic links (#98)
* add func to create symbolic link with RelativePath as destination * add failing test with relative sym link * fix handling of relative symbolic link * formatting * add createSymbolicLink with RelativePath to FileSysteming protocol * add private helper func for creating symbolic links with absolute and relative path * formatting * Make authentication optional --------- Co-authored-by: fortmarek <marekfort@me.com>
1 parent 95fccd7 commit c60a236

File tree

4 files changed

+66
-13
lines changed

4 files changed

+66
-13
lines changed

Sources/FileSystem/FileSystem.swift

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,12 @@ public protocol FileSysteming {
220220
/// - to: The path the symlink points to.
221221
func createSymbolicLink(from: AbsolutePath, to: AbsolutePath) async throws
222222

223+
/// Creates a relative symlink.
224+
/// - Parameters:
225+
/// - from: The path where the symlink is created.
226+
/// - to: The relative path the symlink points to.
227+
func createSymbolicLink(from: AbsolutePath, to: RelativePath) async throws
228+
223229
/// Given a symlink, it resolves it returning the path to the file or directory the symlink is pointing to.
224230
/// - Parameter symlinkPath: The absolute path to the symlink.
225231
/// - Returns: The resolved path.
@@ -542,10 +548,18 @@ public struct FileSystem: FileSysteming, Sendable {
542548
}
543549

544550
public func createSymbolicLink(from: AbsolutePath, to: AbsolutePath) async throws {
545-
logger?.debug("Creating symbolic link from \(from.pathString) to \(to.pathString).")
551+
try await createSymbolicLink(fromPathString: from.pathString, toPathString: to.pathString)
552+
}
553+
554+
public func createSymbolicLink(from: AbsolutePath, to: RelativePath) async throws {
555+
try await createSymbolicLink(fromPathString: from.pathString, toPathString: to.pathString)
556+
}
557+
558+
private func createSymbolicLink(fromPathString: String, toPathString: String) async throws {
559+
logger?.debug("Creating symbolic link from \(fromPathString) to \(toPathString).")
546560
try await NIOFileSystem.FileSystem.shared.createSymbolicLink(
547-
at: FilePath(from.pathString),
548-
withDestination: FilePath(to.pathString)
561+
at: FilePath(fromPathString),
562+
withDestination: FilePath(toPathString)
549563
)
550564
}
551565

Sources/Glob/GlobSearch.swift

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,17 +83,15 @@ public func search(
8383
}
8484

8585
let path = baseURL.absoluteString.removingPercentEncoding ?? baseURL.absoluteString
86-
let symbolicLinkDestination: URL?
87-
if let symbolicLinkDestinationAbsoluteString = try? FileManager.default
88-
.destinationOfSymbolicLink(atPath: path)
89-
{
90-
symbolicLinkDestination = URL(string: symbolicLinkDestinationAbsoluteString)
91-
} else {
92-
symbolicLinkDestination = nil
93-
}
86+
let symbolicLinkDestination = URL(filePath: path).resolvingSymlinksInPath()
9487
var isDirectory: ObjCBool = false
88+
89+
let symbolicLinkDestinationPath: String = symbolicLinkDestination
90+
.path()
91+
.removingPercentEncoding ?? symbolicLinkDestination.path()
92+
9593
guard FileManager.default.fileExists(
96-
atPath: symbolicLinkDestination?.absoluteString ?? path,
94+
atPath: symbolicLinkDestinationPath,
9795
isDirectory: &isDirectory
9896
),
9997
isDirectory.boolValue

Tests/FileSystemTests/FileSystemTests.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,40 @@ final class FileSystemTests: XCTestCase, @unchecked Sendable {
856856
}
857857
}
858858

859+
func test_glob_with_relative_symlink() async throws {
860+
try await subject.runInTemporaryDirectory(prefix: "FileSystem") { temporaryDirectory in
861+
// Given
862+
let frameworkDir = temporaryDirectory.appending(component: "Framework")
863+
let sourceDir = frameworkDir.appending(component: "Source")
864+
let spmResourcesDir = sourceDir.appending(component: "SwiftPackageResources")
865+
let modelSymLinkPath = spmResourcesDir.appending(component: "MyModel.xcdatamodeld")
866+
867+
let actualResourcesDir = frameworkDir.appending(component: "Resources")
868+
let actualModelPath = actualResourcesDir.appending(component: "MyModel.xcdatamodeld")
869+
let versionPath = actualModelPath.appending(component: "MyModel_0.xcdatamodel")
870+
871+
try await subject.makeDirectory(at: spmResourcesDir)
872+
try await subject.makeDirectory(at: actualResourcesDir)
873+
try await subject.makeDirectory(at: actualModelPath)
874+
try await subject.touch(versionPath)
875+
876+
let relativeActualModelPath = try RelativePath(validating: "../../Resources/MyModel.xcdatamodeld")
877+
try await subject.createSymbolicLink(from: modelSymLinkPath, to: relativeActualModelPath)
878+
879+
// When
880+
let got = try await subject.glob(
881+
directory: modelSymLinkPath,
882+
include: ["*.xcdatamodel"]
883+
)
884+
.collect()
885+
.sorted()
886+
887+
// Then
888+
XCTAssertEqual(got.count, 1)
889+
XCTAssertEqual(got.map(\.basename), [versionPath.basename])
890+
}
891+
}
892+
859893
func test_glob_with_double_directory_wildcard() async throws {
860894
try await subject.runInTemporaryDirectory(prefix: "FileSystem") { temporaryDirectory in
861895
// Given

Tuist.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
11
import ProjectDescription
22

3-
let tuist = Tuist(fullHandle: "tuist/FileSystem")
3+
let tuist = Tuist(
4+
fullHandle: "tuist/FileSystem",
5+
project: .tuist(
6+
generationOptions: .options(
7+
optionalAuthentication: true
8+
)
9+
)
10+
)

0 commit comments

Comments
 (0)