Skip to content

Make Configuration.workingDirectory optional #74

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
Jun 13, 2025
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
17 changes: 5 additions & 12 deletions Sources/Subprocess/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ public struct Configuration: Sendable {
/// The environment to use when running the executable.
public var environment: Environment
/// The working directory to use when running the executable.
public var workingDirectory: FilePath
/// If this property is `nil`, the subprocess will inherit the working directory from the parent process.
public var workingDirectory: FilePath?
/// The platform specific options to use when
/// running the subprocess.
public var platformOptions: PlatformOptions
Expand All @@ -54,7 +55,7 @@ public struct Configuration: Sendable {
self.executable = executable
self.arguments = arguments
self.environment = environment
self.workingDirectory = workingDirectory ?? .currentWorkingDirectory
self.workingDirectory = workingDirectory
self.platformOptions = platformOptions
}

Expand Down Expand Up @@ -107,7 +108,7 @@ extension Configuration: CustomStringConvertible, CustomDebugStringConvertible {
executable: \(self.executable.description),
arguments: \(self.arguments.description),
environment: \(self.environment.description),
workingDirectory: \(self.workingDirectory),
workingDirectory: \(self.workingDirectory?.string ?? ""),
platformOptions: \(self.platformOptions.description(withIndent: 1))
)
"""
Expand All @@ -119,7 +120,7 @@ extension Configuration: CustomStringConvertible, CustomDebugStringConvertible {
executable: \(self.executable.debugDescription),
arguments: \(self.arguments.debugDescription),
environment: \(self.environment.debugDescription),
workingDirectory: \(self.workingDirectory),
workingDirectory: \(self.workingDirectory?.string ?? ""),
platformOptions: \(self.platformOptions.description(withIndent: 1))
)
"""
Expand Down Expand Up @@ -714,14 +715,6 @@ internal struct CreatedPipe: ~Copyable {
}
}

extension FilePath {
static var currentWorkingDirectory: Self {
let path = getcwd(nil, 0)!
defer { free(path) }
return .init(String(cString: path))
}
}

extension Optional where Wrapped: Collection {
func withOptionalUnsafeBufferPointer<Result>(
_ body: ((UnsafeBufferPointer<Wrapped.Element>)?) throws -> Result
Expand Down
23 changes: 14 additions & 9 deletions Sources/Subprocess/Platforms/Subprocess+Darwin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -349,9 +349,13 @@ extension Configuration {
}

// Setup cwd
let intendedWorkingDir = self.workingDirectory.string
let chdirError: Int32 = intendedWorkingDir.withPlatformString { workDir in
return posix_spawn_file_actions_addchdir_np(&fileActions, workDir)
let chdirError: Int32
if let intendedWorkingDir = self.workingDirectory?.string {
chdirError = intendedWorkingDir.withPlatformString { workDir in
return posix_spawn_file_actions_addchdir_np(&fileActions, workDir)
}
} else {
chdirError = 0
}

// Error handling
Expand Down Expand Up @@ -457,12 +461,13 @@ extension Configuration {
errorRead: errorReadFileDescriptor,
errorWrite: errorWriteFileDescriptor
)
let workingDirectory = self.workingDirectory.string
guard Configuration.pathAccessible(workingDirectory, mode: F_OK) else {
throw SubprocessError(
code: .init(.failedToChangeWorkingDirectory(workingDirectory)),
underlyingError: .init(rawValue: ENOENT)
)
if let workingDirectory = self.workingDirectory?.string {
guard Configuration.pathAccessible(workingDirectory, mode: F_OK) else {
throw SubprocessError(
code: .init(.failedToChangeWorkingDirectory(workingDirectory)),
underlyingError: .init(rawValue: ENOENT)
)
}
}
throw SubprocessError(
code: .init(.executableNotFound(self.executable.description)),
Expand Down
16 changes: 8 additions & 8 deletions Sources/Subprocess/Platforms/Subprocess+Linux.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,10 @@ extension Configuration {
errorReadFileDescriptor?.platformDescriptor() ?? -1,
]

let workingDirectory: String = self.workingDirectory.string
// Spawn
var pid: pid_t = 0
let spawnError: CInt = possibleExecutablePath.withCString { exePath in
return workingDirectory.withCString { workingDir in
return (self.workingDirectory?.string).withOptionalCString { workingDir in
return supplementaryGroups.withOptionalUnsafeBufferPointer { sgroups in
return fileDescriptors.withUnsafeBufferPointer { fds in
return _subprocess_fork_exec(
Expand Down Expand Up @@ -173,12 +172,13 @@ extension Configuration {
errorRead: errorReadFileDescriptor,
errorWrite: errorWriteFileDescriptor
)
let workingDirectory = self.workingDirectory.string
guard Configuration.pathAccessible(workingDirectory, mode: F_OK) else {
throw SubprocessError(
code: .init(.failedToChangeWorkingDirectory(workingDirectory)),
underlyingError: .init(rawValue: ENOENT)
)
if let workingDirectory = self.workingDirectory?.string {
guard Configuration.pathAccessible(workingDirectory, mode: F_OK) else {
throw SubprocessError(
code: .init(.failedToChangeWorkingDirectory(workingDirectory)),
underlyingError: .init(rawValue: ENOENT)
)
}
}
throw SubprocessError(
code: .init(.executableNotFound(self.executable.description)),
Expand Down
24 changes: 13 additions & 11 deletions Sources/Subprocess/Platforms/Subprocess+Windows.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ extension Configuration {
try environment.withCString(
encodedAs: UTF16.self
) { environmentW in
try intendedWorkingDir.withNTPathRepresentation { intendedWorkingDirW in
try intendedWorkingDir.withOptionalNTPathRepresentation { intendedWorkingDirW in
let created = CreateProcessW(
applicationNameW,
UnsafeMutablePointer<WCHAR>(mutating: commandAndArgsW),
Expand Down Expand Up @@ -223,7 +223,7 @@ extension Configuration {
try environment.withCString(
encodedAs: UTF16.self
) { environmentW in
try intendedWorkingDir.withNTPathRepresentation { intendedWorkingDirW in
try intendedWorkingDir.withOptionalNTPathRepresentation { intendedWorkingDirW in
let created = CreateProcessWithLogonW(
usernameW,
domainW,
Expand Down Expand Up @@ -769,7 +769,7 @@ extension Configuration {
applicationName: String?,
commandAndArgs: String,
environment: String,
intendedWorkingDir: String
intendedWorkingDir: String?
) {
// Prepare environment
var env: [String: String] = [:]
Expand Down Expand Up @@ -806,19 +806,21 @@ extension Configuration {
commandAndArgs
) = try self.generateWindowsCommandAndAgruments()
// Validate workingDir
guard Self.pathAccessible(self.workingDirectory.string) else {
throw SubprocessError(
code: .init(
.failedToChangeWorkingDirectory(self.workingDirectory.string)
),
underlyingError: nil
)
if let workingDirectory = self.workingDirectory?.string {
guard Self.pathAccessible(workingDirectory) else {
throw SubprocessError(
code: .init(
.failedToChangeWorkingDirectory(workingDirectory)
),
underlyingError: nil
)
}
}
return (
applicationName: applicationName,
commandAndArgs: commandAndArgs,
environment: environmentString,
intendedWorkingDir: self.workingDirectory.string
intendedWorkingDir: self.workingDirectory?.string
)
}

Expand Down
8 changes: 5 additions & 3 deletions Sources/_SubprocessCShims/process_shims.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,9 +397,11 @@ static int _subprocess_posix_spawn_fallback(
if (rc != 0) { return rc; }
}
// Setup working directory
rc = _subprocess_addchdir_np(&file_actions, working_directory);
if (rc != 0) {
return rc;
if (working_directory != NULL) {
rc = _subprocess_addchdir_np(&file_actions, working_directory);
if (rc != 0) {
return rc;
}
}

// Close parent side
Expand Down
Loading