Skip to content
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

[Experimental][DNM] Use SwiftSystem for file operations #221

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
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
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

option(BUILD_SHARED_LIBS "Build shared libraries by default" YES)

if(FIND_PM_DEPS)
find_package(SwiftSystem CONFIG REQUIRED)
endif()

find_package(dispatch QUIET)
find_package(Foundation QUIET)
find_package(Threads QUIET)
Expand Down
16 changes: 16 additions & 0 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"object": {
"pins": [
{
"package": "swift-system",
"repositoryURL": "https://github.com/apple/swift-system.git",
"state": {
"branch": null,
"revision": "2bc160bfe34d843ae5ff47168080add24dfd7eac",
"version": "0.0.2"
}
}
]
},
"version": 1
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove this file

10 changes: 5 additions & 5 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ let package = Package(
name: "TSCTestSupport",
targets: ["TSCTestSupport"]),
],
dependencies: [],
dependencies: [
.package(url: "https://github.com/apple/swift-system.git", .upToNextMinor(from: "0.0.1"))
],
targets: [

// MARK: Tools support core targets
Expand All @@ -44,7 +46,8 @@ let package = Package(
.target(
/** TSCBasic support library */
name: "TSCBasic",
dependencies: ["TSCLibc", "TSCclibc"]),
dependencies: ["TSCLibc", "TSCclibc",
.product(name: "SystemPackage", package: "swift-system")]),
.target(
/** Abstractions for common operations, should migrate to TSCBasic */
name: "TSCUtility",
Expand Down Expand Up @@ -82,8 +85,5 @@ let package = Package(
TSCBasic.cxxSettings = [
.define("_CRT_SECURE_NO_WARNINGS", .when(platforms: [.windows])),
]
TSCBasic.linkerSettings = [
.linkedLibrary("Pathcch", .when(platforms: [.windows])),
]
}
#endif
7 changes: 3 additions & 4 deletions Sources/TSCBasic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,16 @@ target_compile_options(TSCBasic PUBLIC
# Ignore secure function warnings on Windows.
"$<$<PLATFORM_ID:Windows>:SHELL:-Xcc -D_CRT_SECURE_NO_WARNINGS>")
target_link_libraries(TSCBasic PUBLIC
TSCLibc)
TSCLibc
SwiftSystem)
target_link_libraries(TSCBasic PRIVATE
TSCclibc)
TSCclibc)
if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin)
if(Foundation_FOUND)
target_link_libraries(TSCBasic PUBLIC
Foundation)
endif()
endif()
target_link_libraries(TSCBasic PRIVATE
$<$<PLATFORM_ID:Windows>:Pathcch>)
# NOTE(compnerd) workaround for CMake not setting up include flags yet
set_target_properties(TSCBasic PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})
Expand Down
112 changes: 51 additions & 61 deletions Sources/TSCBasic/FileSystem.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See http://swift.org/LICENSE.txt for license information
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

import TSCLibc
import Foundation
import Dispatch
import SystemPackage

public struct FileSystemError: Error, Equatable {
public enum Kind: Equatable {
Expand Down Expand Up @@ -86,23 +86,34 @@ extension FileSystemError: CustomNSError {
}
}

public extension FileSystemError {
init(errno: Int32, _ path: AbsolutePath) {
extension FileSystemError.Kind {
public static func errno(_ errno: Errno) -> FileSystemError.Kind {
switch errno {
case TSCLibc.EACCES:
self.init(.invalidAccess, path)
case TSCLibc.EISDIR:
self.init(.isDirectory, path)
case TSCLibc.ENOENT:
self.init(.noEntry, path)
case TSCLibc.ENOTDIR:
self.init(.notDirectory, path)
default:
self.init(.unknownOSError, path)
case .permissionDenied: return .invalidAccess
case .isDirectory: return.isDirectory
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing space?

case .noSuchFileOrDirectory: return .noEntry
case .notDirectory: return .notDirectory
default: return .unknownOSError
}
}
}

public extension FileSystemError {
init(errno: Errno, _ path: AbsolutePath) {
self.init(.errno(errno), path)
}
init(errno: Int32, _ path: AbsolutePath) {
self.init(errno: Errno(rawValue: errno), path)
}
}

func withFileSystemError<Result>(path: AbsolutePath, _ body: () throws -> Result) throws -> Result {
do { return try body() }
catch let errno as Errno {
throw FileSystemError(errno: errno, path)
}
}

/// Defines the file modes.
public enum FileMode {

Expand Down Expand Up @@ -284,7 +295,7 @@ private class LocalFileSystem: FileSystem {

func isExecutableFile(_ path: AbsolutePath) -> Bool {
// Our semantics doesn't consider directories.
return (self.isFile(path) || self.isSymlink(path)) && FileManager.default.isExecutableFile(atPath: path.pathString)
return (self.isFile(path) || self.isSymlink(path)) && FileManager.default.isExecutableFile(atPath: path.pathString)
}

func exists(_ path: AbsolutePath, followSymlink: Bool) -> Bool {
Expand Down Expand Up @@ -377,60 +388,39 @@ private class LocalFileSystem: FileSystem {
}

func createSymbolicLink(_ path: AbsolutePath, pointingAt destination: AbsolutePath, relative: Bool) throws {
let destString = relative ? destination.relative(to: path.parentDirectory).pathString : destination.pathString
let destString = relative ? try 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")
if fp == nil {
throw FileSystemError(errno: errno, path)
}
defer { fclose(fp) }

// Read the data one block at a time.
let data = BufferedOutputByteStream()
var tmpBuffer = [UInt8](repeating: 0, count: 1 << 12)
while true {
let n = fread(&tmpBuffer, 1, tmpBuffer.count, fp)
if n < 0 {
if errno == EINTR { continue }
throw FileSystemError(.ioError(code: errno), path)
}
if n == 0 {
let errno = ferror(fp)
if errno != 0 {
throw FileSystemError(.ioError(code: errno), path)
try withFileSystemError(path: path) {
let data = BufferedOutputByteStream()
// Open the file.
let fd = try FileDescriptor.open(path.filepath, .readOnly)
var tmpBuffer = [UInt8](repeating: 0, count: 1 << 12)
try fd.closeAfter {
while true {
// Read the data one block at a time.
let n = try tmpBuffer.withUnsafeMutableBytes {
try fd.read(into: $0)
}
guard n > 0 else { break }
data <<< tmpBuffer[0..<n]
}
break
}
data <<< tmpBuffer[0..<n]
return data.bytes
}

return data.bytes
}

func writeFileContents(_ path: AbsolutePath, bytes: ByteString) throws {
// Open the file.
let fp = fopen(path.pathString, "wb")
if fp == nil {
throw FileSystemError(errno: errno, path)
}
defer { fclose(fp) }

// Write the data in one chunk.
var contents = bytes.contents
while true {
let n = fwrite(&contents, 1, contents.count, fp)
if n < 0 {
if errno == EINTR { continue }
throw FileSystemError(.ioError(code: errno), path)
}
if n != contents.count {
throw FileSystemError(.unknownOSError, path)
try withFileSystemError(path: path) {
// Open the file.
let fd = try FileDescriptor.open(path.filepath, .writeOnly, options: [.create, .truncate], permissions: [
.ownerReadWrite, .groupReadWrite, .otherRead
])
_ = try fd.closeAfter {
try fd.writeAll(bytes.contents)
}
break
}
}

Expand Down Expand Up @@ -803,7 +793,7 @@ public class InMemoryFileSystem: FileSystem {
throw FileSystemError(.alreadyExistsAtDestination, path)
}

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

contents.entries[path.basename] = Node(.symlink(destination))
}
Expand Down Expand Up @@ -981,11 +971,11 @@ public class RerootedFileSystemView: FileSystem {

/// Adjust the input path for the underlying file system.
private func formUnderlyingPath(_ path: AbsolutePath) -> AbsolutePath {
if path == AbsolutePath.root {
if path.isRoot {
return root
} else {
// FIXME: Optimize?
return root.appending(RelativePath(String(path.pathString.dropFirst(1))))
return root.appending(RelativePath(path.filepath.removingRoot()))
}
}

Expand Down
Loading