Skip to content

Commit 5fd01de

Browse files
authored
Merge pull request #1588 from vlm/deprecate-standalone-currentWorkingDirectory
Deprecate stand-alone currentWorkingDirectory
2 parents 4f59f05 + 241d43d commit 5fd01de

15 files changed

+98
-34
lines changed

Sources/Basic/FileSystem.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import POSIX
1212
import SPMLibc
13+
import Foundation
1314

1415
public enum FileSystemError: Swift.Error {
1516
/// Access to the path is denied.
@@ -135,6 +136,13 @@ public protocol FileSystem: class {
135136
// more data than just the name here.
136137
func getDirectoryContents(_ path: AbsolutePath) throws -> [String]
137138

139+
/// Get the current working directory (similar to `getcwd(3)`), which can be
140+
/// different for different (virtualized) implementations of a FileSystem.
141+
/// The current working directory can be empty if e.g. the directory became
142+
/// unavailable while the current process was still working in it.
143+
/// This follows the POSIX `getcwd(3)` semantics.
144+
var currentWorkingDirectory: AbsolutePath? { get }
145+
138146
/// Create the given directory.
139147
func createDirectory(_ path: AbsolutePath) throws
140148

@@ -218,6 +226,11 @@ private class LocalFileSystem: FileSystem {
218226
return Basic.isSymlink(path)
219227
}
220228

229+
var currentWorkingDirectory: AbsolutePath? {
230+
let cwdStr = FileManager.default.currentDirectoryPath
231+
return try? AbsolutePath(validating: cwdStr)
232+
}
233+
221234
func getDirectoryContents(_ path: AbsolutePath) throws -> [String] {
222235
guard let dir = SPMLibc.opendir(path.asString) else {
223236
throw FileSystemError(errno: errno)
@@ -558,6 +571,11 @@ public class InMemoryFileSystem: FileSystem {
558571
return false
559572
}
560573

574+
/// Virtualized current working directory.
575+
public var currentWorkingDirectory: AbsolutePath? {
576+
return AbsolutePath("/")
577+
}
578+
561579
public func getDirectoryContents(_ path: AbsolutePath) throws -> [String] {
562580
guard let node = try getNode(path) else {
563581
throw FileSystemError.noEntry
@@ -733,6 +751,11 @@ public class RerootedFileSystemView: FileSystem {
733751
return underlyingFileSystem.isExecutableFile(formUnderlyingPath(path))
734752
}
735753

754+
/// Virtualized current working directory.
755+
public var currentWorkingDirectory: AbsolutePath? {
756+
return AbsolutePath("/")
757+
}
758+
736759
public func getDirectoryContents(_ path: AbsolutePath) throws -> [String] {
737760
return try underlyingFileSystem.getDirectoryContents(formUnderlyingPath(path))
738761
}

Sources/Basic/PathShims.swift

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,8 @@ public func unlink(_ path: AbsolutePath) throws {
112112
guard rv == 0 else { throw SystemError.unlink(errno, path.asString) }
113113
}
114114

115-
/// The current working directory of the process (same as returned by POSIX' `getcwd()` function or Foundation's
116-
/// `currentDirectoryPath` method).
117-
/// FIXME: This should probably go onto `FileSystem`, under the assumption that each file system has its own notion of
118-
/// the `current` working directory.
115+
/// The current working directory of the processs.
116+
@available(*, deprecated, renamed: "localFileSystem.currentWorkingDirectory")
119117
public var currentWorkingDirectory: AbsolutePath {
120118
let cwdStr = FileManager.default.currentDirectoryPath
121119
return AbsolutePath(cwdStr)
@@ -214,13 +212,17 @@ public class RecursibleDirectoryContentsGenerator: IteratorProtocol, Sequence {
214212
extension AbsolutePath {
215213
/// Returns a path suitable for display to the user (if possible, it is made
216214
/// to be relative to the current working directory).
217-
public func prettyPath(cwd: AbsolutePath = currentWorkingDirectory) -> String {
215+
public func prettyPath(cwd: AbsolutePath? = localFileSystem.currentWorkingDirectory) -> String {
216+
guard let dir = cwd else {
217+
// No current directory, display as is.
218+
return self.asString
219+
}
218220
// FIXME: Instead of string prefix comparison we should add a proper API
219221
// to AbsolutePath to determine ancestry.
220-
if self == cwd {
222+
if self == dir {
221223
return "."
222-
} else if self.asString.hasPrefix(cwd.asString + "/") {
223-
return "./" + self.relative(to: cwd).asString
224+
} else if self.asString.hasPrefix(dir.asString + "/") {
225+
return "./" + self.relative(to: dir).asString
224226
} else {
225227
return self.asString
226228
}

Sources/Basic/Process.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ public final class Process: ObjectIdentifierProtocol {
204204
// FIXME: This can be cached.
205205
let envSearchPaths = getEnvSearchPaths(
206206
pathString: getenv("PATH"),
207-
currentWorkingDirectory: currentWorkingDirectory
207+
currentWorkingDirectory: localFileSystem.currentWorkingDirectory
208208
)
209209
// Lookup the executable.
210210
let value = lookupExecutablePath(

Sources/Basic/misc.swift

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,18 @@ public func exec(path: String, args: [String]) throws {
3434
/// - Returns: List of search paths.
3535
public func getEnvSearchPaths(
3636
pathString: String?,
37-
currentWorkingDirectory cwd: AbsolutePath
37+
currentWorkingDirectory: AbsolutePath?
3838
) -> [AbsolutePath] {
3939
// Compute search paths from PATH variable.
40-
return (pathString ?? "").split(separator: ":").map(String.init).map({ pathString in
40+
return (pathString ?? "").split(separator: ":").map(String.init).compactMap({ pathString in
4141
// If this is an absolute path, we're done.
4242
if pathString.first == "/" {
4343
return AbsolutePath(pathString)
4444
}
4545
// Otherwise convert it into absolute path relative to the working directory.
46+
guard let cwd = currentWorkingDirectory else {
47+
return nil
48+
}
4649
return AbsolutePath(pathString, relativeTo: cwd)
4750
})
4851
}
@@ -57,20 +60,32 @@ public func getEnvSearchPaths(
5760
///
5861
/// - Parameters:
5962
/// - filename: The name of the file to find.
60-
/// - cwd: The current working directory to look in.
63+
/// - currentWorkingDirectory: The current working directory to look in.
6164
/// - searchPaths: The additional search paths to look in if not found in cwd.
6265
/// - Returns: Valid path to executable if present, otherwise nil.
6366
public func lookupExecutablePath(
6467
filename value: String?,
65-
currentWorkingDirectory cwd: AbsolutePath = currentWorkingDirectory,
68+
currentWorkingDirectory: AbsolutePath? = localFileSystem.currentWorkingDirectory,
6669
searchPaths: [AbsolutePath] = []
6770
) -> AbsolutePath? {
71+
6872
// We should have a value to continue.
6973
guard let value = value, !value.isEmpty else {
7074
return nil
7175
}
72-
// We have a value, but it could be an absolute or a relative path.
73-
let path = AbsolutePath(value, relativeTo: cwd)
76+
77+
let path: AbsolutePath
78+
if let cwd = currentWorkingDirectory {
79+
// We have a value, but it could be an absolute or a relative path.
80+
path = AbsolutePath(value, relativeTo: cwd)
81+
} else if let absPath = try? AbsolutePath(validating: value) {
82+
// Current directory not being available is not a problem
83+
// for the absolute-specified paths.
84+
path = absPath
85+
} else {
86+
return nil
87+
}
88+
7489
if localFileSystem.isExecutableFile(path) {
7590
return path
7691
}

Sources/Commands/Destination.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public struct Destination {
5959
///
6060
/// - Parameter originalWorkingDirectory: The working directory when the program was launched.
6161
private static func hostBinDir(
62-
originalWorkingDirectory: AbsolutePath = currentWorkingDirectory
62+
originalWorkingDirectory: AbsolutePath? = localFileSystem.currentWorkingDirectory
6363
) -> AbsolutePath {
6464
#if Xcode
6565
// For Xcode, set bin directory to the build directory containing the fake
@@ -74,15 +74,17 @@ public struct Destination {
7474
return AbsolutePath(#file).parentDirectory
7575
.parentDirectory.parentDirectory.appending(components: ".build", hostTargetTriple, "debug")
7676
#else
77-
return AbsolutePath(
78-
CommandLine.arguments[0], relativeTo: originalWorkingDirectory).parentDirectory
77+
guard let cwd = originalWorkingDirectory else {
78+
return try! AbsolutePath(validating: CommandLine.arguments[0]).parentDirectory
79+
}
80+
return AbsolutePath(CommandLine.arguments[0], relativeTo: cwd).parentDirectory
7981
#endif
8082
}
8183

8284
/// The destination describing the host OS.
8385
public static func hostDestination(
8486
_ binDir: AbsolutePath? = nil,
85-
originalWorkingDirectory: AbsolutePath = currentWorkingDirectory
87+
originalWorkingDirectory: AbsolutePath? = localFileSystem.currentWorkingDirectory
8688
) throws -> Destination {
8789
// Select the correct binDir.
8890
let binDir = binDir ?? Destination.hostBinDir(

Sources/Commands/SwiftPackageTool.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public class SwiftPackageTool: SwiftTool<PackageToolOptions> {
4747
print(Versioning.currentVersion.completeDisplayString)
4848

4949
case .initPackage:
50-
let initPackage = try InitPackage(destinationPath: currentWorkingDirectory, packageType: options.initMode)
50+
let initPackage = try InitPackage(destinationPath: localFileSystem.currentWorkingDirectory!, packageType: options.initMode)
5151
initPackage.progressReporter = { message in
5252
print(message)
5353
}

Sources/Commands/SwiftRunTool.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@ public class SwiftRunTool: SwiftTool<RunToolOptions> {
157157
/// Executes the executable at the specified path.
158158
private func run(_ excutablePath: AbsolutePath, arguments: [String]) throws {
159159
// Make sure we are running from the original working directory.
160-
if originalWorkingDirectory != currentWorkingDirectory {
160+
let cwd: AbsolutePath? = localFileSystem.currentWorkingDirectory
161+
if cwd == nil || originalWorkingDirectory != cwd {
161162
try POSIX.chdir(originalWorkingDirectory.asString)
162163
}
163164

@@ -169,8 +170,15 @@ public class SwiftRunTool: SwiftTool<RunToolOptions> {
169170
private func isValidSwiftFilePath(_ path: String) -> Bool {
170171
guard path.hasSuffix(".swift") else { return false }
171172
//FIXME: Return false when the path is not a valid path string.
172-
let absolutePath = path.first == "/" ?
173-
AbsolutePath(path) : AbsolutePath(currentWorkingDirectory, path)
173+
let absolutePath: AbsolutePath
174+
if path.first == "/" {
175+
absolutePath = AbsolutePath(path)
176+
} else {
177+
guard let cwd = localFileSystem.currentWorkingDirectory else {
178+
return false
179+
}
180+
absolutePath = AbsolutePath(cwd, path)
181+
}
174182
return localFileSystem.isFile(absolutePath)
175183
}
176184

Sources/Commands/SwiftTestTool.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ public class SwiftTestTool: SwiftTool<TestToolOptions> {
292292
private static func xctestHelperPath() -> AbsolutePath {
293293
let xctestHelperBin = "swiftpm-xctest-helper"
294294
let binDirectory = AbsolutePath(CommandLine.arguments.first!,
295-
relativeTo: currentWorkingDirectory).parentDirectory
295+
relativeTo: localFileSystem.currentWorkingDirectory!).parentDirectory
296296
// XCTestHelper tool is installed in libexec.
297297
let maybePath = binDirectory.parentDirectory.appending(components: "libexec", "swift", "pm", xctestHelperBin)
298298
if isFile(maybePath) {

Sources/Commands/SwiftTool.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ public class SwiftTool<Options: ToolOptions> {
212212
/// - parameter args: The command line arguments to be passed to this tool.
213213
public init(toolName: String, usage: String, overview: String, args: [String], seeAlso: String? = nil) {
214214
// Capture the original working directory ASAP.
215-
originalWorkingDirectory = currentWorkingDirectory
215+
originalWorkingDirectory = localFileSystem.currentWorkingDirectory!
216216

217217
// Create the parser.
218218
parser = ArgumentParser(
@@ -367,7 +367,7 @@ public class SwiftTool<Options: ToolOptions> {
367367
self.packageRoot = packageRoot
368368
self.buildPath = getEnvBuildPath() ??
369369
customBuildPath ??
370-
(packageRoot ?? currentWorkingDirectory).appending(component: ".build")
370+
(packageRoot ?? localFileSystem.currentWorkingDirectory!).appending(component: ".build")
371371

372372
if options.chdir != nil {
373373
diagnostics.emit(data: ChdirDeprecatedDiagnostic())
@@ -735,9 +735,11 @@ extension BuildSubset {
735735
/// Returns path of the nearest directory containing the manifest file w.r.t
736736
/// current working directory.
737737
private func findPackageRoot() -> AbsolutePath? {
738+
guard var root = localFileSystem.currentWorkingDirectory else {
739+
return nil
740+
}
738741
// FIXME: It would be nice to move this to a generalized method which takes path and predicate and
739742
// finds the lowest path for which the predicate is true.
740-
var root = currentWorkingDirectory
741743
while !isFile(root.appending(component: Manifest.filename)) {
742744
root = root.parentDirectory
743745
guard !root.isRoot else {
@@ -751,7 +753,7 @@ private func getEnvBuildPath() -> AbsolutePath? {
751753
// Don't rely on build path from env for SwiftPM's own tests.
752754
guard POSIX.getenv("IS_SWIFTPM_TEST") == nil else { return nil }
753755
guard let env = POSIX.getenv("SWIFTPM_BUILD_DIR") else { return nil }
754-
return AbsolutePath(env, relativeTo: currentWorkingDirectory)
756+
return AbsolutePath(env, relativeTo: localFileSystem.currentWorkingDirectory!)
755757
}
756758

757759
/// Returns the sandbox profile to be used when parsing manifest on macOS.

Sources/Commands/UserToolchain.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public struct UserToolchain: Toolchain {
127127

128128
// Get the search paths from PATH.
129129
let envSearchPaths = getEnvSearchPaths(
130-
pathString: getenv("PATH"), currentWorkingDirectory: currentWorkingDirectory)
130+
pathString: getenv("PATH"), currentWorkingDirectory: localFileSystem.currentWorkingDirectory)
131131

132132
func lookup(fromEnv: String) -> AbsolutePath? {
133133
return lookupExecutablePath(

Sources/SourceControl/GitRepository.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,10 @@ private class GitFileSystemView: FileSystem {
602602
return false
603603
}
604604

605+
public var currentWorkingDirectory: AbsolutePath? {
606+
return AbsolutePath("/")
607+
}
608+
605609
func getDirectoryContents(_ path: AbsolutePath) throws -> [String] {
606610
guard let entry = try getEntry(path) else {
607611
throw FileSystemError.noEntry

Sources/SourceControl/InMemoryGitRepository.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,10 @@ extension InMemoryGitRepository: FileSystem {
203203
return head.fileSystem.isExecutableFile(path)
204204
}
205205

206+
public var currentWorkingDirectory: AbsolutePath? {
207+
return AbsolutePath("/")
208+
}
209+
206210
public func getDirectoryContents(_ path: AbsolutePath) throws -> [String] {
207211
return try head.fileSystem.getDirectoryContents(path)
208212
}

Sources/Utility/ArgumentParser.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,11 @@ public struct PathArgument: ArgumentKind {
197197

198198
public init(argument: String) throws {
199199
// FIXME: This should check for invalid paths.
200-
path = AbsolutePath(argument, relativeTo: currentWorkingDirectory)
200+
if let cwd = localFileSystem.currentWorkingDirectory {
201+
path = AbsolutePath(argument, relativeTo: cwd)
202+
} else {
203+
path = try AbsolutePath(validating: argument)
204+
}
201205
}
202206

203207
public static var completion: ShellCompletion = .filename

Tests/BasicTests/PathShimTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class PathShimTests : XCTestCase {
9393

9494
func testCurrentWorkingDirectory() {
9595
// Test against what POSIX returns, at least for now.
96-
let cwd = currentWorkingDirectory;
96+
let cwd = localFileSystem.currentWorkingDirectory!
9797
XCTAssertEqual(cwd, AbsolutePath(getcwd()))
9898
}
9999

Tests/UtilityTests/ArgumentParserTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -464,21 +464,21 @@ class ArgumentParserTests: XCTestCase {
464464
// Test that relative path is resolved.
465465
do {
466466
let actual = try! SwiftPMProduct.TestSupportExecutable.execute(["pathArgumentTest", "some/path"]).chomp()
467-
let expected = currentWorkingDirectory.appending(RelativePath("some/path")).asString
467+
let expected = localFileSystem.currentWorkingDirectory!.appending(RelativePath("some/path")).asString
468468
XCTAssertEqual(actual, expected)
469469
}
470470

471471
// Test that relative path starting with ./ is resolved.
472472
do {
473473
let actual = try! SwiftPMProduct.TestSupportExecutable.execute(["pathArgumentTest", "./some/path"]).chomp()
474-
let expected = currentWorkingDirectory.appending(RelativePath("./some/path")).asString
474+
let expected = localFileSystem.currentWorkingDirectory!.appending(RelativePath("./some/path")).asString
475475
XCTAssertEqual(actual, expected)
476476
}
477477

478478
// Test that relative path starting with ../ is resolved.
479479
do {
480480
let actual = try! SwiftPMProduct.TestSupportExecutable.execute(["pathArgumentTest", "../other/path"]).chomp()
481-
let expected = currentWorkingDirectory.appending(RelativePath("../other/path")).asString
481+
let expected = localFileSystem.currentWorkingDirectory!.appending(RelativePath("../other/path")).asString
482482
XCTAssertEqual(actual, expected)
483483
}
484484

0 commit comments

Comments
 (0)