Skip to content

Commit 53c735c

Browse files
authored
Merge pull request #3031 from tomerd/sync-and-fix-tsc
adjust to latest TSC FS APIs
2 parents b565edc + 1a0a9f3 commit 53c735c

File tree

12 files changed

+231
-111
lines changed

12 files changed

+231
-111
lines changed

Sources/Build/BuildOperation.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
125125
if localFileSystem.exists(oldBuildPath) {
126126
try localFileSystem.removeFileTree(oldBuildPath)
127127
}
128-
try createSymlink(oldBuildPath, pointingAt: buildParameters.buildPath, relative: true)
128+
try localFileSystem.createSymbolicLink(oldBuildPath, pointingAt: buildParameters.buildPath, relative: true)
129129
}
130130

131131
/// Compute the llbuild target name using the given subset.

Sources/SPMTestSupport/InMemoryGitRepository.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ extension InMemoryGitRepository: FileSystem {
211211
}
212212

213213
public func changeCurrentWorkingDirectory(to path: AbsolutePath) throws {
214-
fatalError("Unsupported")
214+
throw FileSystemError.unsupported
215215
}
216216

217217
public var homeDirectory: AbsolutePath {
@@ -229,6 +229,10 @@ extension InMemoryGitRepository: FileSystem {
229229
public func createDirectory(_ path: AbsolutePath, recursive: Bool) throws {
230230
try head.fileSystem.createDirectory(path, recursive: recursive)
231231
}
232+
233+
public func createSymbolicLink(_ path: AbsolutePath, pointingAt destination: AbsolutePath, relative: Bool) throws {
234+
throw FileSystemError.unsupported
235+
}
232236

233237
public func readFileContents(_ path: AbsolutePath) throws -> ByteString {
234238
return try head.fileSystem.readFileContents(path)

Sources/SourceControl/GitRepository.swift

+4
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,10 @@ private class GitFileSystemView: FileSystem {
772772
func createDirectory(_ path: AbsolutePath, recursive: Bool) throws {
773773
throw FileSystemError.unsupported
774774
}
775+
776+
func createSymbolicLink(_ path: AbsolutePath, pointingAt destination: AbsolutePath, relative: Bool) throws {
777+
throw FileSystemError.unsupported
778+
}
775779

776780
func writeFileContents(_ path: AbsolutePath, bytes: ByteString) throws {
777781
throw FileSystemError.unsupported

Sources/Workspace/Workspace.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -841,7 +841,7 @@ extension Workspace {
841841
// FIXME: We should probably just warn in case we fail to create
842842
// this symlink, which could happen if there is some non-symlink
843843
// entry at this location.
844-
try createSymlink(symLinkPath, pointingAt: path, relative: false)
844+
try fileSystem.createSymbolicLink(symLinkPath, pointingAt: path, relative: false)
845845
}
846846
}
847847

Tests/CommandsTests/PackageToolTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ final class PackageToolTests: XCTestCase {
653653
}
654654

655655
// Create symlink to the dependency.
656-
try createSymlink(depSym, pointingAt: dep)
656+
try fs.createSymbolicLink(depSym, pointingAt: dep, relative: false)
657657

658658
_ = try execute(["resolve"], packagePath: root)
659659
}

Tests/PackageLoadingTests/PackageBuilderTests.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class PackageBuilderTests: XCTestCase {
6767
let linkDestPath = path.appending(components: "link.swift")
6868
let linkPath = sources.appending(components: "link.swift")
6969
try fs.writeFileContents(linkDestPath, bytes: "")
70-
try createSymlink(linkPath, pointingAt: linkDestPath)
70+
try fs.createSymbolicLink(linkPath, pointingAt: linkDestPath, relative: false)
7171
try fs.removeFileTree(linkDestPath)
7272

7373
let manifest = Manifest.createV4Manifest(
@@ -98,7 +98,7 @@ class PackageBuilderTests: XCTestCase {
9898
try fs.writeFileContents(foo.appending(components: "foo.swift"), bytes: "")
9999

100100
// Create a symlink to foo.
101-
try createSymlink(bar, pointingAt: foo)
101+
try fs.createSymbolicLink(bar, pointingAt: foo, relative: false)
102102

103103
let manifest = Manifest.createV4Manifest(
104104
name: "pkg",

swift-tools-support-core/Sources/TSCBasic/FileSystem.swift

+68-29
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,13 @@ public protocol FileSystem: class {
168168
/// - recursive: If true, create missing parent directories if possible.
169169
func createDirectory(_ path: AbsolutePath, recursive: Bool) throws
170170

171+
/// Creates a symbolic link of the source path at the target path
172+
/// - Parameters:
173+
/// - path: The path at which to create the link.
174+
/// - destination: The path to which the link points to.
175+
/// - relative: If `relative` is true, the symlink contents will be a relative path, otherwise it will be absolute.
176+
func createSymbolicLink(_ path: AbsolutePath, pointingAt destination: AbsolutePath, relative: Bool) throws
177+
171178
// FIXME: This is obviously not a very efficient or flexible API.
172179
//
173180
/// Get the contents of a file.
@@ -350,6 +357,11 @@ private class LocalFileSystem: FileSystem {
350357
try FileManager.default.createDirectory(atPath: path.pathString, withIntermediateDirectories: recursive, attributes: [:])
351358
}
352359

360+
func createSymbolicLink(_ path: AbsolutePath, pointingAt destination: AbsolutePath, relative: Bool) throws {
361+
let destString = relative ? destination.relative(to: path.parentDirectory).pathString : destination.pathString
362+
try FileManager.default.createSymbolicLink(atPath: path.pathString, withDestinationPath: destString)
363+
}
364+
353365
func readFileContents(_ path: AbsolutePath) throws -> ByteString {
354366
// Open the file.
355367
let fp = fopen(path.pathString, "rb")
@@ -492,6 +504,7 @@ public class InMemoryFileSystem: FileSystem {
492504
private enum NodeContents {
493505
case file(ByteString)
494506
case directory(DirectoryContents)
507+
case symlink(String)
495508

496509
/// Creates deep copy of the object.
497510
func copy() -> NodeContents {
@@ -500,6 +513,8 @@ public class InMemoryFileSystem: FileSystem {
500513
return .file(bytes)
501514
case .directory(let contents):
502515
return .directory(contents.copy())
516+
case .symlink(let path):
517+
return .symlink(path)
503518
}
504519
}
505520
}
@@ -519,19 +534,9 @@ public class InMemoryFileSystem: FileSystem {
519534
return contents
520535
}
521536
}
522-
// Used to ensure that DispatchQueues are releassed when they are no longer in use.
523-
private struct WeakReference<Value: AnyObject> {
524-
weak var reference: Value?
525-
526-
init(_ value: Value?) {
527-
self.reference = value
528-
}
529-
}
530537

531538
/// The root filesytem.
532539
private var root: Node
533-
/// A map that keeps weak references to all locked files.
534-
private var lockFiles = Dictionary<AbsolutePath, WeakReference<DispatchQueue>>()
535540
/// Used to access lockFiles in a thread safe manner.
536541
private let lockFilesLock = Lock()
537542

@@ -547,7 +552,7 @@ public class InMemoryFileSystem: FileSystem {
547552
}
548553

549554
/// Get the node corresponding to the given path.
550-
private func getNode(_ path: AbsolutePath) throws -> Node? {
555+
private func getNode(_ path: AbsolutePath, followSymlink: Bool = true) throws -> Node? {
551556
func getNodeInternal(_ path: AbsolutePath) throws -> Node? {
552557
// If this is the root node, return it.
553558
if path.isRoot {
@@ -565,7 +570,17 @@ public class InMemoryFileSystem: FileSystem {
565570
}
566571

567572
// Return the directory entry.
568-
return contents.entries[path.basename]
573+
let node = contents.entries[path.basename]
574+
575+
switch node?.contents {
576+
case .directory, .file:
577+
return node
578+
case .symlink(let destination):
579+
let destination = AbsolutePath(destination, relativeTo: path.parentDirectory)
580+
return followSymlink ? try getNodeInternal(destination) : node
581+
case .none:
582+
return nil
583+
}
569584
}
570585

571586
// Get the node that corresponds to the path.
@@ -576,7 +591,10 @@ public class InMemoryFileSystem: FileSystem {
576591

577592
public func exists(_ path: AbsolutePath, followSymlink: Bool) -> Bool {
578593
do {
579-
return try getNode(path) != nil
594+
switch try getNode(path, followSymlink: followSymlink)?.contents {
595+
case .file, .directory, .symlink: return true
596+
case .none: return false
597+
}
580598
} catch {
581599
return false
582600
}
@@ -605,9 +623,14 @@ public class InMemoryFileSystem: FileSystem {
605623
}
606624

607625
public func isSymlink(_ path: AbsolutePath) -> Bool {
608-
// FIXME: Always return false until in-memory implementation
609-
// gets symbolic link semantics.
610-
return false
626+
do {
627+
if case .symlink? = try getNode(path, followSymlink: false)?.contents {
628+
return true
629+
}
630+
return false
631+
} catch {
632+
return false
633+
}
611634
}
612635

613636
public func isExecutableFile(_ path: AbsolutePath) -> Bool {
@@ -690,6 +713,26 @@ public class InMemoryFileSystem: FileSystem {
690713
contents.entries[path.basename] = Node(.directory(DirectoryContents()))
691714
}
692715

716+
public func createSymbolicLink(_ path: AbsolutePath, pointingAt destination: AbsolutePath, relative: Bool) throws {
717+
// Create directory to destination parent.
718+
guard let destinationParent = try getNode(path.parentDirectory) else {
719+
throw FileSystemError.noEntry
720+
}
721+
722+
// Check that the parent is a directory.
723+
guard case .directory(let contents) = destinationParent.contents else {
724+
throw FileSystemError.notDirectory
725+
}
726+
727+
guard contents.entries[path.basename] == nil else {
728+
throw FileSystemError.alreadyExistsAtDestination
729+
}
730+
731+
let destination = relative ? destination.relative(to: path.parentDirectory).pathString : destination.pathString
732+
733+
contents.entries[path.basename] = Node(.symlink(destination))
734+
}
735+
693736
public func readFileContents(_ path: AbsolutePath) throws -> ByteString {
694737
// Get the node.
695738
guard let node = try getNode(path) else {
@@ -798,18 +841,8 @@ public class InMemoryFileSystem: FileSystem {
798841
}
799842

800843
public func withLock<T>(on path: AbsolutePath, type: FileLock.LockType = .exclusive, _ body: () throws -> T) throws -> T {
801-
802-
let fileQueue: DispatchQueue = lockFilesLock.withLock {
803-
if let queueReference = lockFiles[path], let queue = queueReference.reference {
804-
return queue
805-
} else {
806-
let queue = DispatchQueue(label: "org.swift.swiftpm.in-memory-file-system.file-queue", attributes: .concurrent)
807-
lockFiles[path] = WeakReference(queue)
808-
return queue
809-
}
810-
}
811-
812-
return try fileQueue.sync(flags: type == .exclusive ? .barrier : .init() , execute: body)
844+
// FIXME: Lock individual files once resolving symlinks is thread-safe.
845+
return try lockFilesLock.withLock(body)
813846
}
814847
}
815848

@@ -895,6 +928,12 @@ public class RerootedFileSystemView: FileSystem {
895928
return try underlyingFileSystem.createDirectory(path, recursive: recursive)
896929
}
897930

931+
public func createSymbolicLink(_ path: AbsolutePath, pointingAt destination: AbsolutePath, relative: Bool) throws {
932+
let path = formUnderlyingPath(path)
933+
let destination = formUnderlyingPath(destination)
934+
return try underlyingFileSystem.createSymbolicLink(path, pointingAt: destination, relative: relative)
935+
}
936+
898937
public func readFileContents(_ path: AbsolutePath) throws -> ByteString {
899938
return try underlyingFileSystem.readFileContents(formUnderlyingPath(path))
900939
}
@@ -905,7 +944,7 @@ public class RerootedFileSystemView: FileSystem {
905944
}
906945

907946
public func removeFileTree(_ path: AbsolutePath) throws {
908-
try underlyingFileSystem.removeFileTree(path)
947+
try underlyingFileSystem.removeFileTree(formUnderlyingPath(path))
909948
}
910949

911950
public func chmod(_ mode: FileMode, path: AbsolutePath, options: Set<FileMode.Option>) throws {

swift-tools-support-core/Sources/TSCBasic/PathShims.swift

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public func makeDirectories(_ path: AbsolutePath) throws {
6161

6262
/// Creates a symbolic link at `path` whose content points to `dest`. If `relative` is true, the symlink contents will
6363
/// be a relative path, otherwise it will be absolute.
64+
@available(*, deprecated, renamed: "localFileSystem.createSymbolicLink")
6465
public func createSymlink(_ path: AbsolutePath, pointingAt dest: AbsolutePath, relative: Bool = true) throws {
6566
let destString = relative ? dest.relative(to: path.parentDirectory).pathString : dest.pathString
6667
try FileManager.default.createSymbolicLink(atPath: path.pathString, withDestinationPath: destString)

0 commit comments

Comments
 (0)