Skip to content

adjust to latest TSC FS APIs #3031

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/Build/BuildOperation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
if localFileSystem.exists(oldBuildPath) {
try localFileSystem.removeFileTree(oldBuildPath)
}
try createSymlink(oldBuildPath, pointingAt: buildParameters.buildPath, relative: true)
try localFileSystem.createSymbolicLink(oldBuildPath, pointingAt: buildParameters.buildPath, relative: true)
}

/// Compute the llbuild target name using the given subset.
Expand Down
6 changes: 5 additions & 1 deletion Sources/SPMTestSupport/InMemoryGitRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ extension InMemoryGitRepository: FileSystem {
}

public func changeCurrentWorkingDirectory(to path: AbsolutePath) throws {
fatalError("Unsupported")
throw FileSystemError.unsupported
}

public var homeDirectory: AbsolutePath {
Expand All @@ -229,6 +229,10 @@ extension InMemoryGitRepository: FileSystem {
public func createDirectory(_ path: AbsolutePath, recursive: Bool) throws {
try head.fileSystem.createDirectory(path, recursive: recursive)
}

public func createSymbolicLink(_ path: AbsolutePath, pointingAt destination: AbsolutePath, relative: Bool) throws {
throw FileSystemError.unsupported
}

public func readFileContents(_ path: AbsolutePath) throws -> ByteString {
return try head.fileSystem.readFileContents(path)
Expand Down
4 changes: 4 additions & 0 deletions Sources/SourceControl/GitRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,10 @@ private class GitFileSystemView: FileSystem {
func createDirectory(_ path: AbsolutePath, recursive: Bool) throws {
throw FileSystemError.unsupported
}

func createSymbolicLink(_ path: AbsolutePath, pointingAt destination: AbsolutePath, relative: Bool) throws {
throw FileSystemError.unsupported
}

func writeFileContents(_ path: AbsolutePath, bytes: ByteString) throws {
throw FileSystemError.unsupported
Expand Down
2 changes: 1 addition & 1 deletion Sources/Workspace/Workspace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,7 @@ extension Workspace {
// FIXME: We should probably just warn in case we fail to create
// this symlink, which could happen if there is some non-symlink
// entry at this location.
try createSymlink(symLinkPath, pointingAt: path, relative: false)
try fileSystem.createSymbolicLink(symLinkPath, pointingAt: path, relative: false)
}
}

Expand Down
2 changes: 1 addition & 1 deletion Tests/CommandsTests/PackageToolTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ final class PackageToolTests: XCTestCase {
}

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

_ = try execute(["resolve"], packagePath: root)
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/PackageLoadingTests/PackageBuilderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class PackageBuilderTests: XCTestCase {
let linkDestPath = path.appending(components: "link.swift")
let linkPath = sources.appending(components: "link.swift")
try fs.writeFileContents(linkDestPath, bytes: "")
try createSymlink(linkPath, pointingAt: linkDestPath)
try fs.createSymbolicLink(linkPath, pointingAt: linkDestPath, relative: false)
try fs.removeFileTree(linkDestPath)

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

// Create a symlink to foo.
try createSymlink(bar, pointingAt: foo)
try fs.createSymbolicLink(bar, pointingAt: foo, relative: false)

let manifest = Manifest.createV4Manifest(
name: "pkg",
Expand Down
97 changes: 68 additions & 29 deletions swift-tools-support-core/Sources/TSCBasic/FileSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,13 @@ public protocol FileSystem: class {
/// - recursive: If true, create missing parent directories if possible.
func createDirectory(_ path: AbsolutePath, recursive: Bool) throws

/// Creates a symbolic link of the source path at the target path
/// - Parameters:
/// - path: The path at which to create the link.
/// - destination: The path to which the link points to.
/// - relative: If `relative` is true, the symlink contents will be a relative path, otherwise it will be absolute.
func createSymbolicLink(_ path: AbsolutePath, pointingAt destination: AbsolutePath, relative: Bool) throws

// FIXME: This is obviously not a very efficient or flexible API.
//
/// Get the contents of a file.
Expand Down Expand Up @@ -350,6 +357,11 @@ private class LocalFileSystem: FileSystem {
try FileManager.default.createDirectory(atPath: path.pathString, withIntermediateDirectories: recursive, attributes: [:])
}

func createSymbolicLink(_ path: AbsolutePath, pointingAt destination: AbsolutePath, relative: Bool) throws {
let destString = relative ? destination.relative(to: path.parentDirectory).pathString : destination.pathString
try FileManager.default.createSymbolicLink(atPath: path.pathString, withDestinationPath: destString)
}

func readFileContents(_ path: AbsolutePath) throws -> ByteString {
// Open the file.
let fp = fopen(path.pathString, "rb")
Expand Down Expand Up @@ -492,6 +504,7 @@ public class InMemoryFileSystem: FileSystem {
private enum NodeContents {
case file(ByteString)
case directory(DirectoryContents)
case symlink(String)

/// Creates deep copy of the object.
func copy() -> NodeContents {
Expand All @@ -500,6 +513,8 @@ public class InMemoryFileSystem: FileSystem {
return .file(bytes)
case .directory(let contents):
return .directory(contents.copy())
case .symlink(let path):
return .symlink(path)
}
}
}
Expand All @@ -519,19 +534,9 @@ public class InMemoryFileSystem: FileSystem {
return contents
}
}
// Used to ensure that DispatchQueues are releassed when they are no longer in use.
private struct WeakReference<Value: AnyObject> {
weak var reference: Value?

init(_ value: Value?) {
self.reference = value
}
}

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

Expand All @@ -547,7 +552,7 @@ public class InMemoryFileSystem: FileSystem {
}

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

// Return the directory entry.
return contents.entries[path.basename]
let node = contents.entries[path.basename]

switch node?.contents {
case .directory, .file:
return node
case .symlink(let destination):
let destination = AbsolutePath(destination, relativeTo: path.parentDirectory)
return followSymlink ? try getNodeInternal(destination) : node
case .none:
return nil
}
}

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

public func exists(_ path: AbsolutePath, followSymlink: Bool) -> Bool {
do {
return try getNode(path) != nil
switch try getNode(path, followSymlink: followSymlink)?.contents {
case .file, .directory, .symlink: return true
case .none: return false
}
} catch {
return false
}
Expand Down Expand Up @@ -605,9 +623,14 @@ public class InMemoryFileSystem: FileSystem {
}

public func isSymlink(_ path: AbsolutePath) -> Bool {
// FIXME: Always return false until in-memory implementation
// gets symbolic link semantics.
return false
do {
if case .symlink? = try getNode(path, followSymlink: false)?.contents {
return true
}
return false
} catch {
return false
}
}

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

public func createSymbolicLink(_ path: AbsolutePath, pointingAt destination: AbsolutePath, relative: Bool) throws {
// Create directory to destination parent.
guard let destinationParent = try getNode(path.parentDirectory) else {
throw FileSystemError.noEntry
}

// Check that the parent is a directory.
guard case .directory(let contents) = destinationParent.contents else {
throw FileSystemError.notDirectory
}

guard contents.entries[path.basename] == nil else {
throw FileSystemError.alreadyExistsAtDestination
}

let destination = relative ? destination.relative(to: path.parentDirectory).pathString : destination.pathString

contents.entries[path.basename] = Node(.symlink(destination))
}

public func readFileContents(_ path: AbsolutePath) throws -> ByteString {
// Get the node.
guard let node = try getNode(path) else {
Expand Down Expand Up @@ -798,18 +841,8 @@ public class InMemoryFileSystem: FileSystem {
}

public func withLock<T>(on path: AbsolutePath, type: FileLock.LockType = .exclusive, _ body: () throws -> T) throws -> T {

let fileQueue: DispatchQueue = lockFilesLock.withLock {
if let queueReference = lockFiles[path], let queue = queueReference.reference {
return queue
} else {
let queue = DispatchQueue(label: "org.swift.swiftpm.in-memory-file-system.file-queue", attributes: .concurrent)
lockFiles[path] = WeakReference(queue)
return queue
}
}

return try fileQueue.sync(flags: type == .exclusive ? .barrier : .init() , execute: body)
// FIXME: Lock individual files once resolving symlinks is thread-safe.
return try lockFilesLock.withLock(body)
}
}

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

public func createSymbolicLink(_ path: AbsolutePath, pointingAt destination: AbsolutePath, relative: Bool) throws {
let path = formUnderlyingPath(path)
let destination = formUnderlyingPath(destination)
return try underlyingFileSystem.createSymbolicLink(path, pointingAt: destination, relative: relative)
}

public func readFileContents(_ path: AbsolutePath) throws -> ByteString {
return try underlyingFileSystem.readFileContents(formUnderlyingPath(path))
}
Expand All @@ -905,7 +944,7 @@ public class RerootedFileSystemView: FileSystem {
}

public func removeFileTree(_ path: AbsolutePath) throws {
try underlyingFileSystem.removeFileTree(path)
try underlyingFileSystem.removeFileTree(formUnderlyingPath(path))
}

public func chmod(_ mode: FileMode, path: AbsolutePath, options: Set<FileMode.Option>) throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public func makeDirectories(_ path: AbsolutePath) throws {

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