diff --git a/Sources/System/FilePath/FilePath.swift b/Sources/System/FilePath/FilePath.swift index c2797f5e..5e93fa8b 100644 --- a/Sources/System/FilePath/FilePath.swift +++ b/Sources/System/FilePath/FilePath.swift @@ -62,6 +62,18 @@ public struct FilePath { // @available(macOS 10.16, iOS 14.0, watchOS 7.0, tvOS 14.0, *) extension FilePath { + + /// Returns the current working directory of this process. + /// + /// - Warning: This value is global to the proess and care should be taken to make sure it does not unexpectedly change. + public static func currentWorkingDirectory() throws -> FilePath { + guard let cwd = system_getcwd(nil, 0) else { + throw Errno.current + } + defer { system_free(cwd) } + return FilePath(platformString: cwd) + } + /// The length of the file path, excluding the null terminator. public var length: Int { _storage.length } } diff --git a/Sources/System/Internals/Syscalls.swift b/Sources/System/Internals/Syscalls.swift index 453c02fc..6e76f610 100644 --- a/Sources/System/Internals/Syscalls.swift +++ b/Sources/System/Internals/Syscalls.swift @@ -123,3 +123,24 @@ internal func system_pipe(_ fds: UnsafeMutablePointer) -> CInt { return pipe(fds) } #endif + +#if !os(Windows) +internal func system_getcwd(_ buf: UnsafeMutablePointer?, _ size: size_t) -> UnsafeMutablePointer? { +#if ENABLE_MOCKING + if mockingEnabled { + /// I'm not really sure how to mock this since `buf` is passed in uninitialized and it needs to return something + fatalError() + } +#endif + return getcwd(buf, size) +} +#endif + +#if !os(Windows) +internal func system_free(_ ptr: UnsafeMutableRawPointer?) { +#if ENABLE_MOCKING + if mockingEnabled { _ = _mock(ptr) } +#endif + free(ptr) +} +#endif diff --git a/Tests/SystemTests/FilePathTests/FilePathTest.swift b/Tests/SystemTests/FilePathTests/FilePathTest.swift index 93bc3504..6c92c11e 100644 --- a/Tests/SystemTests/FilePathTests/FilePathTest.swift +++ b/Tests/SystemTests/FilePathTests/FilePathTest.swift @@ -72,5 +72,11 @@ final class FilePathTest: XCTestCase { } } } + + func testCurrentWorkingDirectory() { + XCTAssertEqual( + try FilePath.currentWorkingDirectory().string, + FileManager.default.currentDirectoryPath) + } }