### Complete Environment Setup Example Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/environment.md Illustrates setting up an environment by inheriting and modifying, or by creating a completely custom environment. The configured environment can then be used with the `run` function. ```swift // Inherit and modify let env1 = Environment.inherit .updating(["DEBUG": "1", "LOG_LEVEL": "INFO"]) // Custom environment let env2 = Environment.custom([ "PATH": "/usr/bin:/bin", "HOME": "/tmp", "SHELL": "/bin/sh" ]) // Use with run let result = try await run( .name("env"), environment: env1, output: .string(limit: 4096) ) ``` -------------------------------- ### Example Usage of Configuration Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/configuration.md Demonstrates creating a `Configuration` object and using it with the `run` function. This example sets specific arguments, environment variables, and a working directory. ```swift let config = Configuration( .name("grep"), arguments: ["pattern", "file.txt"], environment: .inherit.updating(["GREP_OPTIONS": "--color=never"]), workingDirectory: FilePath("/home/user"), platformOptions: PlatformOptions() ) let result = try await run(config, output: .string(limit: 8192)) print(result.standardOutput ?? "") ``` -------------------------------- ### Complete Subprocess Execution Example Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/execution.md Demonstrates a full workflow including starting a subprocess, writing to its stdin, reading from stdout, and handling results. ```swift let result = try await run( .path("/my/server"), input: .inputWriter, output: .sequence, error: .string(limit: 4096) ) { execution in print("Process \(execution.processIdentifier.value) started") // Write to stdin try await execution.standardInputWriter.write("hello\n") // Read output var lineCount = 0 for try await buffer in execution.standardOutput { lineCount += 1 } try await execution.standardInputWriter.finish() return lineCount } print("Exit: \(result.terminationStatus)") print("Lines: \(result.closureResult)") if let err = result.standardError { print("Stderr: \(err)") } ``` -------------------------------- ### Multi-Step Teardown Sequence Example Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/teardown.md Demonstrates a complex teardown sequence involving multiple steps, including sending signals and graceful shutdowns, with different durations. This example includes platform-specific configurations for Unix and Windows. ```swift var options = PlatformOptions() #if !os(Windows) options.createSession = true options.teardownSequence = [ .send(signal: .interrupt, toProcessGroup: true, allowedDurationToNextStep: .milliseconds(500)), .gracefulShutDown(toProcessGroup: true, allowedDurationToNextStep: .seconds(3)), .send(signal: .kill, toProcessGroup: true, allowedDurationToNextStep: .milliseconds(100)) ] #else options.teardownSequence = [ .gracefulShutDown(allowedDurationToNextStep: .seconds(5)) ] #endif let result = try await run( .name("long-running-task"), platformOptions: options, output: .string(limit: 1024) ) ``` -------------------------------- ### Complete Subprocess Configuration Example Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/configuration.md Demonstrates how to configure a subprocess with custom environment variables, working directory, and platform-specific options. This is useful for setting up complex server processes. ```swift var platformOptions = PlatformOptions() #if !os(Windows) platformOptions.createSession = true platformOptions.teardownSequence = [ .gracefulShutDown(allowedDurationToNextStep: .seconds(5)) ] #endif let config = Configuration( executable: .name("my-server"), arguments: ["--port", "8080", "--workers", "4"], environment: .inherit .updating(["DEBUG": "1"]) .updating(["LOG_LEVEL": "INFO"]) .updating(["DATABASE_URL": "postgres://localhost/mydb"]), workingDirectory: FilePath("/home/app"), platformOptions: platformOptions ) let result = try await run( config, input: .none, output: .string(limit: 16384), error: .string(limit: 4096) ) print("Exit: \(result.terminationStatus)") print("Output: \(result.standardOutput ?? "")") if let err = result.standardError { print("Errors: \(err)") } ``` -------------------------------- ### Complete PlatformOptions Usage Example Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/platform-options.md Demonstrates setting various platform-specific and general options for subprocess creation, including conditional settings for Unix and macOS, and a teardown sequence. ```swift var options = PlatformOptions() // Unix-specific options #if !os(Windows) options.userID = 1000 options.groupID = 1000 options.processGroupID = 0 options.createSession = true #if os(macOS) options.qualityOfService = .utility #endif #endif // All platforms options.teardownSequence = [ .gracefulShutDown(allowedDurationToNextStep: .seconds(5)) ] let result = try await run( .name("server"), platformOptions: options, output: .string(limit: 1024) ) ``` -------------------------------- ### Run Overload with Configuration Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/configuration.md Shows the signature for a `run` function overload that accepts a `Configuration` object. This simplifies calling subprocesses with complex setups. ```swift public func run( _ configuration: Configuration, input: Input = .none, output: Output, error: Error = .discarded ) async throws -> ExecutionResult ``` -------------------------------- ### Run a Process and Collect Output Source: https://github.com/swiftlang/swift-subprocess/blob/main/README.md Use this for simple cases where you need to run a command and get its complete output. It returns an ExecutionResult containing process info and collected output. ```swift import Subprocess let result = try await run(.name("ls"), output: .string(limit: 4096)) print(result.processIdentifier) // e.g. 1234 print(result.terminationStatus) // e.g. exited(0) print(result.standardOutput) // e.g. Optional("LICENSE\nPackage.swift\n...") ``` -------------------------------- ### Collect Output as Bytes with Error Handling Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/run-function.md This example demonstrates running a command and collecting its standard output as bytes, while also capturing standard error as a string. It's useful when dealing with binary output or when you need to inspect error messages separately. ```swift let result = try await run( .path("/bin/cat"), arguments: ["file.txt"], output: .bytes(limit: 1024 * 1024), error: .string(limit: 4096) ) if let error = result.standardError { print("stderr: \(error)") } ``` -------------------------------- ### Foundation Integration with Data Input/Output Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/README.md Utilize the SubprocessFoundation trait for seamless integration with Foundation's Data type. This example shows how to pass Data as input and receive Data as output from a subprocess. ```swift import Subprocess // Use Data-based input/output let data = Data([1, 2, 3]) let result = try await run( .name("hexdump"), input: .data(data), output: .data(limit: 1024) ) ``` ```swift // Write Data to stdin try await execution.standardInputWriter.write(Data([0x48, 0x69])) ``` -------------------------------- ### Customize String Conversion for Output Buffers Source: https://github.com/swiftlang/swift-subprocess/blob/main/README.md This example shows how to customize the conversion of output buffers to strings, allowing for specific buffering policies and encodings. The .strings() method on the output sequence provides these options. ```swift for try await line in execution.standardOutput.strings( bufferingPolicy: .maxLineLength(1024), as: UTF16.self ) { // ... } ``` -------------------------------- ### Error Handling Example Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/subprocess-error.md Demonstrates how to catch and handle `SubprocessError` using a `do-catch` block and a `switch` statement on the error code. ```APIDOC ## Example: Error Handling ```swift do { let result = try await run( .name("myapp"), output: .string(limit: 1024) ) } catch let error as SubprocessError { switch error.code { case .executableNotFound: print("App not found") case .spawnFailed: print("Failed to spawn: \(error)") if let underlyingError = error.underlyingError { print("Underlying: \(underlyingError)") } case .outputLimitExceeded: print("Output too large") case .failedToWriteToSubprocess: print("Stdin write failed: \(error)") default: print("Other error: \(error)") } } catch { print("Unexpected error: \(error)") } ``` ``` -------------------------------- ### Iterating and Accessing Subprocess Output Buffers Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/output-types.md Example demonstrating how to iterate through subprocess output buffers asynchronously and access their raw byte content using `withUnsafeBytes` or directly via the `bytes` property. ```swift for try await buffer in execution.standardOutput { buffer.withUnsafeBytes { ptr in let array = Array(ptr) print("Bytes: \(array)") } let bytes: RawSpan = buffer.bytes // Use bytes directly } ``` -------------------------------- ### Checking Specific Error Codes Example Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/subprocess-error.md Shows a more concise way to catch specific `SubprocessError` codes directly in the `catch` clause. ```APIDOC ## Example: Checking Specific Error Codes ```swift do { let result = try await run(.name("command"), output: .string(limit: 512)) } catch SubprocessError(code: .executableNotFound, _) { print("Command not found") } catch SubprocessError(code: .outputLimitExceeded, _) { print("Too much output") } catch { print("Other error: \(error)") } ``` ``` -------------------------------- ### Stream Process Output Line by Line Source: https://github.com/swiftlang/swift-subprocess/blob/main/README.md Use this when you need to process the output of a command as it becomes available, for example, to react to specific log messages. Ensure the output stream is set to .sequence. ```swift import Subprocess let result = try await run( .path("/usr/bin/tail"), arguments: ["-f", "/path/to/nginx.log"], input: .none, output: .sequence, error: .discarded ) { execution in for try await line in execution.standardOutput.strings() { if line.contains("500") { // Oh no, 500 error } } } ``` -------------------------------- ### Catching failedToChangeWorkingDirectory Error Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/errors.md Use this to handle cases where the subprocess cannot start in the specified working directory. This error is thrown if the directory does not exist, is inaccessible due to permissions, or is not a directory. The error context will contain the path that could not be set. ```swift do { let result = try await run( .name("ls"), workingDirectory: FilePath("/nonexistent"), output: .string(limit: 1024) ) } catch SubprocessError(code: .failedToChangeWorkingDirectory) { print("Working directory not accessible") } ``` -------------------------------- ### Configuration Initializer Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/configuration.md Creates a new Configuration instance with specified parameters. Defaults are provided for arguments, environment, working directory, and platform options. ```swift public init( executable: Executable, arguments: Arguments = [], environment: Environment = .inherit, workingDirectory: FilePath? = nil, platformOptions: PlatformOptions = PlatformOptions() ) ``` -------------------------------- ### Create Executable by Path Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/executable.md Use `Executable.path()` to create an executable configuration using a direct file path. ```swift let exe = Executable.path(FilePath("/usr/bin/grep")) ``` -------------------------------- ### Complete Error Handling for Subprocess Execution Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/termination-status.md Provides a comprehensive example of handling various subprocess termination outcomes, including success, specific error codes, and signals. ```swift let result = try await run( .name("grep"), arguments: ["pattern", "file.txt"], output: .string(limit: 4096), error: .string(limit: 1024) ) switch result.terminationStatus { case .exited(let code) where code == 0: print("Match found: \(result.standardOutput ?? "")") case .exited(1): print("No matches") case .exited(let code): print("Error (code \(code)): \(result.standardError ?? "")") #if !os(Windows) case .signaled(let sig): print("Killed by signal \(sig)") #endif } ``` -------------------------------- ### run(_:arguments:environment:workingDirectory:platformOptions:input:output:error:) Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/run-function.md Executes a subprocess with configurable arguments, environment, working directory, and I/O handling. This is the primary entry point for running external commands. ```APIDOC ## run(_:arguments:environment:workingDirectory:platformOptions:input:output:error:) ### Description Executes a subprocess with configurable arguments, environment, working directory, and I/O handling. This is the primary entry point for running external commands. ### Signature ```swift public func run( _ executable: Executable, arguments: Arguments = [], environment: Environment = .inherit, workingDirectory: FilePath? = nil, platformOptions: PlatformOptions = PlatformOptions(), input: Input = .none, output: Output, error: Error = .discarded ) async throws -> ExecutionResult ``` ### Parameters #### Executable - **executable** (`Executable`) - Required - The executable to locate: `.name("executable")` searches PATH, `.path("/bin/ls")` uses a direct path. #### Arguments - **arguments** (`Arguments`) - Optional - Command-line arguments. Create with `Arguments(["arg1", "arg2"])` or array literal. Defaults to `[]`. #### Environment - **environment** (`Environment`) - Optional - Environment variables for the subprocess. Use `.inherit.updating(["KEY": "value"])` to modify. Defaults to `.inherit`. #### Working Directory - **workingDirectory** (`FilePath?`) - Optional - The working directory for the subprocess. If `nil`, inherits from the parent. Defaults to `nil`. #### Platform Options - **platformOptions** (`PlatformOptions`) - Optional - Platform-specific settings: process group, user ID, teardown sequence, etc. Defaults to `PlatformOptions()`. #### Input - **input** (`Input`) - Optional - Input source: `.none`, `.string(_:)`, `.array(_:)`, `.fileDescriptor(_:closeAfterSpawningProcess:)` or `.inputWriter` (closure-only). Defaults to `.none`. #### Output - **output** (`Output`) - Required - Output collection method: `.discarded`, `.string(limit:)`, `.bytes(limit:)`, `.fileDescriptor(_:)`, or `.sequence` (closure-only). #### Error - **error** (`Error`) - Optional - Error collection method: `.discarded`, `.string(limit:)`, `.bytes(limit:)`, `.fileDescriptor(_:)`, `.sequence` (closure-only), or `.combinedWithOutput`. Defaults to `.discarded`. ### Return Type `ExecutionResult` — Contains: - `processIdentifier: ProcessIdentifier` — The subprocess PID - `terminationStatus: TerminationStatus` — Exit status (`.exited(code)` or `.signaled(signal)` on Unix) - `standardOutput: Output.OutputType` — Collected output (type varies by output option) - `standardError: Error.OutputType` — Collected error (type varies by error option) - `closureResult: Void` — For this overload, always `Void` ### Errors - **spawnFailed**: Process creation failed (permission, resource limits, etc.). Catch with `try catch let error as SubprocessError where error.code == .spawnFailed`. - **executableNotFound**: Executable not found in PATH or given path does not exist. Catch with `error.code == .executableNotFound`. - **failedToChangeWorkingDirectory**: The working directory path is invalid or not accessible. Catch with `error.code == .failedToChangeWorkingDirectory`. - **outputLimitExceeded**: Output exceeds the specified limit. Catch with `error.code == .outputLimitExceeded`. - **failedToReadFromSubprocess**: I/O read error from child. Catch with `error.code == .failedToReadFromSubprocess`. - **failedToMonitorProcess**: Process monitoring failed. Catch with `error.code == .failedToMonitorProcess`. - **asyncIOFailed**: Platform-specific async I/O operation failed. Catch with `error.code == .asyncIOFailed`. ### Examples #### Collect output as a string ```swift let result = try await run( .name("ls"), arguments: ["-la"], output: .string(limit: 4096) ) print(result.standardOutput ?? "") ``` #### Collect output as bytes with error handling ```swift let result = try await run( .path("/bin/cat"), arguments: ["file.txt"], output: .bytes(limit: 1024 * 1024), error: .string(limit: 4096) ) if let error = result.standardError { print("stderr: \(error)") } ``` #### Run with custom environment ```swift let result = try await run( .name("env"), environment: .custom([.init("CUSTOM_VAR"): "value"]), output: .string(limit: 2048) ) ``` #### Run with string input ```swift let result = try await run( .name("cat"), input: .string("Hello, Subprocess!"), output: .string(limit: 4096) ) print(result.standardOutput ?? "") ``` ``` -------------------------------- ### Generate API Documentation Source: https://github.com/swiftlang/swift-subprocess/blob/main/README.md Run this command to view the latest API documentation for the Subprocess target. ```bash swift package --disable-sandbox preview-documentation --target Subprocess ``` -------------------------------- ### Implement Retry Logic for Subprocess Errors Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/errors.md Implement retry logic for transient errors, distinguishing them from permanent errors like `.executableNotFound`. This example retries up to 3 times with increasing delays. ```swift var lastError: SubprocessError? for attempt in 1...3 { do { let result = try await run(.name("flaky-tool"), output: .string(limit: 1024)) print("Success on attempt \(attempt)") return result } catch let error as SubprocessError { // Retry on transient errors; fail immediately on permanent errors if error.code == .executableNotFound { throw error } lastError = error try await Task.sleep(nanoseconds: UInt64(attempt) * 1_000_000_000) } } throw lastError ?? SubprocessError.spawnFailed ``` -------------------------------- ### Define Process Configuration Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/types.md Bundles all necessary information to run a subprocess, including the executable, arguments, environment, working directory, and platform-specific options. Defaults are provided for convenience. ```swift public struct Configuration: Sendable { public var executable: Executable public var arguments: Arguments public var environment: Environment public var workingDirectory: FilePath? public var platformOptions: PlatformOptions public init( executable: Executable, arguments: Arguments = [], environment: Environment = .inherit, workingDirectory: FilePath? = nil, platformOptions: PlatformOptions = PlatformOptions() ) } ``` -------------------------------- ### Accessing Byte Output and Error String Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/execution-result.md Captures subprocess output as bytes and error messages as strings. This example shows how to access the byte count for output and print the error string if present. ```swift // Byte output with error let result2 = try await run( .name("grep"), arguments: ["pattern", "file"], output: .bytes(limit: 8192), error: .string(limit: 2048) ) print("Output: \(result2.standardOutput.count) bytes") if let errStr = result2.standardError { print("Error: \(errStr)") } ``` -------------------------------- ### Configure CreateProcess Flags on Windows Source: https://github.com/swiftlang/swift-subprocess/blob/main/README.md Utilize preSpawnProcessConfigurator to adjust Windows creation flags and startup info, like enabling CREATE_NEW_CONSOLE. ```swift import Darwin import WinSDK var platformOptions = PlatformOptions() platformOptions.preSpawnProcessConfigurator = { creationFlags, startupInfo in creationFlags |= DWORD(CREATE_NEW_CONSOLE) } let result = try await run(.path(...), platformOptions: platformOptions) ``` -------------------------------- ### Customizable Execution with Arguments, Environment, and Working Directory Source: https://github.com/swiftlang/swift-subprocess/blob/main/README.md Run an executable with specific arguments, modified environment variables, and a designated working directory. The environment can inherit from the parent and be updated. ```swift import Subprocess let result = try await run( .path("/bin/ls"), arguments: ["-a"], // Inherit environment values from the parent process // and add NewKey=NewValue environment: .inherit.updating(["NewKey": "NewValue"]), workingDirectory: "/Users/", output: .string(limit: 4096) ) ``` -------------------------------- ### Create Environment Keys Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/environment.md Demonstrates creating type-safe keys for environment variables using string literals or explicit initialization. Keys are case-sensitive on Unix and case-insensitive on Windows. ```swift let key: Environment.Key = "PATH" let key2 = Environment.Key("HOME") ``` -------------------------------- ### Stream Output and Collect Error with Closure Result Source: https://github.com/swiftlang/swift-subprocess/blob/main/README.md This example shows how to stream standard output, collect standard error as a string, and return a custom value from the closure. The closure's return value is accessible via result.closureResult. ```swift let result = try await run( .path("/my/app"), input: .none, output: .sequence, error: .string(limit: 4096) ) { execution in var lineCount = 0 for try await _ in execution.standardOutput.strings() { lineCount += 1 } return lineCount } print(result.closureResult) // The line count returned from the closure. print(result.standardError ?? "") // The captured standard error. ``` -------------------------------- ### Configuration Description Output Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/configuration.md Illustrates the output of printing a `Configuration` object, which conforms to `CustomStringConvertible`. This provides a human-readable representation of the configuration settings. ```swift print(config) // Configuration( // executable: grep, // arguments: ["pattern", "file.txt"], // environment: Inheriting current environment with updates: [...], // workingDirectory: /home/user, // platformOptions: ... // ) ``` -------------------------------- ### Run with String Input Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/run-function.md This snippet shows how to provide string input to a subprocess. The input string is passed to the standard input of the executed command, and its standard output is collected as a string. ```swift let result = try await run( .name("cat"), input: .string("Hello, Subprocess!"), output: .string(limit: 4096) ) print(result.standardOutput ?? "") ``` -------------------------------- ### Create Executable by Name Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/executable.md Use `Executable.name()` to create an executable configuration that searches the PATH environment variable. ```swift let exe = Executable.name("ls") ``` -------------------------------- ### Specify Executable Location Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/configuration.md Use `.name()` to search in the system's PATH or `.path()` to provide an absolute file path for the executable. ```swift .name("executable") // Search in PATH .path(FilePath("/usr/bin/executable")) // Use absolute path ``` -------------------------------- ### Write to Standard Input and Read Standard Output Source: https://github.com/swiftlang/swift-subprocess/blob/main/README.md This snippet demonstrates how to send data to a process's standard input and simultaneously read its standard output. Use .inputWriter for input and .sequence for output. ```swift let result = try await run( .name("cat"), input: .inputWriter, output: .sequence, error: .discarded ) { execution in async let reading: Void = { for try await line in execution.standardOutput.strings() { print(line) // "Hello, Subprocess!" } }() try await execution.standardInputWriter.write("Hello, Subprocess!\n") try await execution.standardInputWriter.finish() try await reading } ``` -------------------------------- ### Environment.custom(_: [[UInt8]]) [Unix only] Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/environment.md Creates a custom environment from raw byte arrays. Unix only; used for non-UTF-8 environment variables. ```APIDOC ## Environment.custom(_: [[UInt8]]) [Unix only] ### Description Creates a custom environment from raw byte arrays. Unix only; used for non-UTF-8 environment variables. ### Method static `custom(_ newValue: [[UInt8]]) -> Self` (Unix only) ### Example ```swift let rawBytes: [[UInt8]] = [...] let env = Environment.custom(rawBytes) ``` ``` -------------------------------- ### Define PlatformOptions Structure Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/types.md Defines the configuration options for running a subprocess, including quality of service, user/group IDs, and custom spawn actions. Used by Configuration and run() functions. ```swift public struct PlatformOptions: Sendable { public var qualityOfService: QualityOfService public var userID: uid_t? public var groupID: gid_t? public var supplementaryGroups: [gid_t]? public var processGroupID: pid_t? public var createSession: Bool public var teardownSequence: [TeardownStep] public var preSpawnProcessConfigurator: ( @Sendable (inout posix_spawnattr_t?, inout posix_spawn_file_actions_t?) throws -> Void )? public init() } ``` -------------------------------- ### Configure Subprocess Execution Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/configuration.md Use the Configuration struct to set executable, arguments, environment, working directory, and platform options for running a subprocess. This is an alternative to passing individual parameters to `run()`. ```swift let config = Configuration( executable: .name("ls"), arguments: ["-la"], environment: .inherit.updating(["LANG": "en_US.UTF-8"]), workingDirectory: FilePath("/home/user"), platformOptions: PlatformOptions() ) let result = try await run(config, output: .string(limit: 4096)) ``` -------------------------------- ### Collect Output as String Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/run-function.md Use this snippet to execute a command and collect its standard output as a string. It specifies the executable name and arguments, and sets the output to be captured as a string with a specified byte limit. ```swift let result = try await run( .name("ls"), arguments: ["-la"], output: .string(limit: 4096) ) print(result.standardOutput ?? "") ``` -------------------------------- ### Configure posix_spawn Attributes on macOS Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/platform-options.md Provides a closure to directly configure low-level `posix_spawn()` attributes and file actions before process creation on macOS. Requires importing `Darwin`. ```swift import Darwin var options = PlatformOptions() options.preSpawnProcessConfigurator = { spawnAttr, fileAttr in var flags: Int16 = 0 posix_spawnattr_getflags(&spawnAttr, &flags) posix_spawnattr_setflags(&spawnAttr, flags | Int16(POSIX_SPAWN_SETSID)) } ``` -------------------------------- ### Environment.custom(_: [Key: String]) Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/environment.md Creates a custom environment with only the specified variables. The parent environment is not inherited. ```APIDOC ## Environment.custom(_: [Key: String]) ### Description Creates a custom environment with only the specified variables. The parent environment is not inherited. ### Method static `custom(_ newValue: [Key: String]) -> Self` ### Parameters #### Request Body - **newValue** (Dictionary) - Required - Dictionary of environment variables. ### Example ```swift let env = Environment.custom([ "HOME": "/home/user", "PATH": "/usr/bin:/bin" ]) ``` ``` -------------------------------- ### Executable.name(_:) Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/executable.md Locates an executable by its name, searching the PATH environment variable. This is a static factory method to create an Executable instance. ```APIDOC ## Executable.name(_:) ### Description Locates the executable by name. The subprocess uses the `PATH` environment variable to search for the executable. ### Method Signature ```swift public static func name(_ executableName: String) -> Self ``` ### Parameters - `executableName` (String) - The name of the executable to locate. ### Returns - `Self` - An `Executable` instance representing the named executable. ### Example ```swift let exe = Executable.name("ls") ``` ``` -------------------------------- ### Run Subprocess - Configuration-Based Overloads Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/README.md These overloads allow you to reuse a pre-defined `Configuration` object for running subprocesses. They offer the same input/output handling as the collected-result API. ```swift public func run( _ configuration: Configuration, input: Input = .none, output: Output, error: Error = .discarded ) async throws -> ExecutionResult ``` -------------------------------- ### Configuration Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/types.md Defines the complete configuration for running a subprocess, including the executable, arguments, environment, working directory, and platform-specific options. ```APIDOC ## Configuration ### Description Defines the complete configuration for running a subprocess, including the executable, arguments, environment, working directory, and platform-specific options. ### Properties - `var executable: Executable` - `var arguments: Arguments` - `var environment: Environment` - `var workingDirectory: FilePath?` - `var platformOptions: PlatformOptions` ### Initializer - `init(executable: Executable, arguments: Arguments = [], environment: Environment = .inherit, workingDirectory: FilePath? = nil, platformOptions: PlatformOptions = PlatformOptions())` ``` -------------------------------- ### Collect Command Output as String Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/README.md Use this to capture the entire standard output of a command as a single string. Specify a limit to prevent excessive memory usage. ```swift import Subprocess let result = try await run( .name("ls"), arguments: ["-la"], output: .string(limit: 4096) ) print(result.standardOutput ?? "") ``` -------------------------------- ### Configure macOS Subprocess Options Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/configuration.md Set the quality of service and configure posix_spawn for macOS subprocesses. This allows for controlling process priority and low-level spawn behavior. ```swift #if os(macOS) // Set quality of service options.qualityOfService = .utility // Direct control over posix_spawn options.preSpawnProcessConfigurator = { spawnAttr, fileAttr in var flags: Int16 = 0 posix_spawnattr_getflags(&spawnAttr, &flags) posix_spawnattr_setflags(&spawnAttr, flags | Int16(POSIX_SPAWN_SETSID)) } #endif ``` -------------------------------- ### run(_:arguments:environment:workingDirectory:platformOptions:input:output:error:body:) Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/run-closure.md Executes a subprocess while a closure manages the running process. The closure receives an `Execution` value for streaming I/O and process control. ```APIDOC ## run(_:arguments:environment:workingDirectory:platformOptions:input:output:error:body:) ### Description Executes a subprocess while a closure manages the running process. The closure receives an `Execution` value for streaming I/O and process control. ### Method `public func run( _ executable: Executable, arguments: Arguments = [], environment: Environment = .inherit, workingDirectory: FilePath? = nil, platformOptions: PlatformOptions = PlatformOptions(), input: Input, output: Output, error: Error, body: (Execution) async throws -> Result ) async throws -> ExecutionResult ### Parameters #### Path Parameters * **executable** (`Executable`) - Required - The executable to locate. #### Query Parameters * **arguments** (`Arguments`) - Optional - Command-line arguments. Defaults to `[]`. * **environment** (`Environment`) - Optional - Environment variables. Defaults to `.inherit`. * **workingDirectory** (`FilePath?`) - Optional - Working directory; `nil` means inherit from parent. Defaults to `nil`. * **platformOptions** (`PlatformOptions`) - Optional - Platform-specific configuration. Defaults to `PlatformOptions()`. * **input** (`Input`) - Required - Input source: `.none`, `.string(_:)`, `.array(_:)`, `.fileDescriptor(_:)`, or `.inputWriter`. * **output** (`Output`) - Required - Output method: `.discarded`, `.string(limit:)`, `.bytes(limit:)`, `.fileDescriptor(_:)`, or `.sequence`. * **error** (`Error`) - Required - Error method: `.discarded`, `.string(limit:)`, `.bytes(limit:)`, `.fileDescriptor(_:)`, `.sequence`, or `.combinedWithOutput`. #### Request Body * **body** (`(Execution) async throws -> Result`) - Required - A closure that runs while the subprocess is active. Receives an `Execution` object for process control and streaming. Must return a value of type `Result` (use `Void` if no result). ### Return Type `ExecutionResult` — Contains: - `processIdentifier: ProcessIdentifier` — The subprocess PID - `terminationStatus: TerminationStatus` — Exit status - `standardOutput: Output.OutputType` — Collected standard output - `standardError: Error.OutputType` — Collected standard error - `closureResult: Result` — The value returned by the closure Call `result.takeClosureResult()` to extract a noncopyable result. ### Errors Same as `run(_:output:error:)` plus: - `failedToWriteToSubprocess`: Write via `standardInputWriter` fails ### Examples #### Stream output line-by-line ```swift let result = try await run( .name("tail"), arguments: ["-f", "logfile.txt"], output: .sequence, error: .discarded ) { execution in for try await line in execution.standardOutput.strings() { print("Log: \(line)") } } ``` #### Write to stdin and read from stdout ```swift let result = try await run( .name("cat"), input: .inputWriter, output: .sequence, error: .discarded ) { execution in async let reading: Void = { for try await line in execution.standardOutput.strings() { print(line) } }() try await execution.standardInputWriter.write("Hello, world!\n") try await execution.standardInputWriter.finish() await reading } ``` #### Stream both stdout and stderr concurrently ```swift try await run( .path("/my/app"), input: .none, output: .sequence, error: .sequence ) { execution in try await withThrowingTaskGroup(of: Void.self) { group in group.addTask { for try await buffer in execution.standardOutput { print("out: \(buffer.count) bytes") } } group.addTask { for try await buffer in execution.standardError { print("err: \(buffer.count) bytes") } } try await group.waitForAll() } } ``` #### Collect error while streaming output ```swift let result = try await run( .name("myapp"), output: .sequence, error: .string(limit: 4096) ) { execution in var lineCount = 0 for try await _ in execution.standardOutput.strings() { lineCount += 1 } return lineCount } print("Lines: \(result.closureResult)") print("Errors: \(result.standardError ?? "")") ``` ### Lifetime Rules The `Execution` object is valid only within the closure. Do not store or return it. The `standardInputWriter`, `standardOutput`, and `standardError` properties are consumed when accessed; a second access returns `nil` or triggers a runtime error. ``` -------------------------------- ### Environment.inherit Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/environment.md Creates an environment that inherits all variables from the current process. Modifications can be made with `updating(_:)`. ```APIDOC ## Environment.inherit ### Description Creates an environment that inherits all variables from the current process. Modifications can be made with `updating(_:)`. ### Method static `inherit` ### Example ```swift let env = Environment.inherit ``` ``` -------------------------------- ### Write to Stdin and Read from Stdout Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/run-closure.md Execute a command, write data to its standard input, and concurrently read from its standard output. This pattern is common for interactive command-line tools. ```swift let result = try await run( .name("cat"), input: .inputWriter, output: .sequence, error: .discarded ) { execution in async let reading: Void = { for try await line in execution.standardOutput.strings() { print(line) } }() try await execution.standardInputWriter.write("Hello, world!\n") try await execution.standardInputWriter.finish() await reading } ``` -------------------------------- ### Input Handling - None Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/README.md Represents no input being provided to the subprocess. This is the default behavior. ```swift InputProtocol.none ``` -------------------------------- ### Configure Multiple Teardown Steps for Unix/Linux Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/configuration.md Define multiple teardown steps for Unix/Linux, including sending signals and graceful shutdown with specified durations. This provides robust process termination. ```swift // Unix: Multiple teardown steps #if !os(Windows) options.teardownSequence = [ .send(signal: .interrupt, allowedDurationToNextStep: .milliseconds(500)), .gracefulShutDown(allowedDurationToNextStep: .seconds(3)), .send(signal: .kill, toProcessGroup: true, allowedDurationToNextStep: .milliseconds(100)) ] #endif ``` -------------------------------- ### String Representation of Executable Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/executable.md Instances of `Executable` provide textual descriptions for both name-based and path-based configurations. ```swift let nameExe = Executable.name("cat") print(nameExe) // "cat" let pathExe = Executable.path(FilePath("/bin/cat")) print(pathExe) // "/bin/cat" print(nameExe.debugDescription) // "executable(cat)" print(pathExe.debugDescription) // "path(/bin/cat)" ``` -------------------------------- ### Configure Platform-Specific Options Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/configuration.md Customize platform-specific settings such as user/group IDs, supplementary groups, session creation, and process teardown sequences. macOS-specific options like quality of service and pre-spawn configuration are also available. ```swift var options = PlatformOptions() // Unix-specific options.userID = 1000 options.groupID = 1000 options.supplementaryGroups = [100, 101] options.processGroupID = 0 options.createSession = true // macOS-specific #if os(macOS) options.qualityOfService = .utility options.preSpawnProcessConfigurator = { spawnAttr, fileAttr in // Direct posix_spawn() configuration } #endif // All platforms options.teardownSequence = [ .gracefulShutDown(allowedDurationToNextStep: .seconds(5)) ] ``` -------------------------------- ### Configuring Graceful Teardown Sequence for Child Processes Source: https://github.com/swiftlang/swift-subprocess/blob/main/README.md Set up a `PlatformOptions` object to define a sequence of teardown steps, including graceful shutdown signals and allowed durations, before forcefully terminating a child process. This is executed when the parent task is cancelled. ```swift let serverTask = Task { var platformOptions = PlatformOptions() platformOptions.teardownSequence = [ .gracefulShutDown(allowedDurationToNextStep: .seconds(5)) ] let result = try await run( .name("server"), platformOptions: platformOptions, output: .string(limit: 1024) ) } // If serverTask is cancelled, Subprocess will: // 1. Attempt a graceful shutdown (SIGTERM on Unix) // 2. Wait up to 5 seconds for the process to exit // 3. Send SIGKILL if the process hasn't exited serverTask.cancel() ``` -------------------------------- ### Configure Environment and Working Directory Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/README.md Customize the execution environment by setting specific environment variables and changing the working directory for the subprocess. Inherits and updates existing environment variables. ```swift let result = try await run( .name("env"), environment: .inherit .updating(["CUSTOM_VAR": "value"]) .updating(["REMOVE_VAR": nil]), workingDirectory: FilePath("/home/user"), output: .string(limit: 2048) ) ``` -------------------------------- ### Reusable Execution Configuration Source: https://github.com/swiftlang/swift-subprocess/blob/main/README.md Create a reusable `Configuration` object for common execution parameters like name and arguments. This configuration can then be used with the `run` function. ```swift let config = Configuration( .name("my-tool"), arguments: ["--verbose"], environment: .inherit ) let result = try await run(config, output: .string(limit: 4096)) ``` -------------------------------- ### Create Custom Environment from Raw Bytes (Unix) Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/environment.md Creates a custom environment from raw byte arrays. This is specific to Unix-like systems and is used for environment variables that are not valid UTF-8. ```swift #if !os(Windows) let rawBytes: [[UInt8]] = [...] let env = Environment.custom(rawBytes) #endif ``` -------------------------------- ### Arguments Initializers Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/arguments.md This section details the various ways to initialize the Arguments struct, allowing for flexible argument construction. ```APIDOC ## init(arrayLiteral:) ### Description Creates arguments from a list literal. Supports array literal syntax. ### Parameters - `elements`: String... - The elements to include in the arguments. ### Example ```swift let args: Arguments = ["--verbose", "--output", "file.txt"] ``` ``` ```APIDOC ## init(_:) ### Description Creates arguments from a string array. ### Parameters - `array`: [String] - The array of strings to be used as arguments. ### Example ```swift let args = Arguments(["arg1", "arg2", "arg3"]) ``` ``` ```APIDOC ## init(executablePathOverride:remainingValues:) ### Description Creates arguments with an optional override for the first argument (argv[0]). If `nil`, the executable path is used automatically. ### Parameters - `executablePathOverride`: String? - Custom value for argv[0], or `nil` to use the executable path. - `remainingValues`: [String] - The remaining command-line arguments. ### Example ```swift let args = Arguments(executablePathOverride: "bash", remainingValues: ["-c", "echo hello"]) ``` ``` ```APIDOC ## init(executablePathOverride:remainingValues:) [Unix only] ### Description Creates arguments from raw byte arrays. Useful for non-UTF-8 arguments on Unix systems. Windows does not support this. ### Parameters - `executablePathOverride`: [UInt8]? - Custom value for argv[0] as raw bytes, or `nil`. - `remainingValues`: [[UInt8]] - The remaining command-line arguments as raw byte arrays. ### Example ```swift let bytes: [[UInt8]] = [[0x61, 0x62, 0x63], [0x64, 0x65, 0x66]] let args = Arguments(bytes) ``` ``` ```APIDOC ## init(_:) [Unix only] ### Description Creates arguments from an array of byte arrays (Unix only). ### Parameters - `array`: [[UInt8]] - The array of byte arrays to be used as arguments. ### Example ```swift let bytes: [[UInt8]] = [[0x61, 0x62, 0x63], [0x64, 0x65, 0x66]] let args = Arguments(bytes) ``` ``` -------------------------------- ### Input Handling - Standard Input Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/README.md Use `InputProtocol.standardInput` to pipe the standard input of the current process to the subprocess. ```swift InputProtocol.standardInput ``` -------------------------------- ### Provide Input to Subprocess Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/configuration.md Configure how data is sent to the subprocess's standard input. Options include no input, a string, a byte array, a file descriptor, the current process's stdin, or writing from a closure. Foundation Data types are also supported when the `SubprocessFoundation` module is enabled. ```swift input: .none input: .string("Hello, subprocess!") input: .string("text", using: UTF8.self) input: .array([0x48, 0x69]) // "Hi" input: .fileDescriptor(fd, closeAfterSpawningProcess: true) input: .standardInput input: .inputWriter // From Data (Foundation) #if SubprocessFoundation input: .data(Data([1, 2, 3])) input: .sequence(dataSequence) input: .sequence(asyncDataSequence) #endif ``` -------------------------------- ### Create Arguments from String Array Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/arguments.md Initialize Arguments directly from a standard Swift array of strings. This is useful when arguments are generated dynamically. ```swift let args = Arguments(["arg1", "arg2", "arg3"]) ``` -------------------------------- ### Create Arguments from Byte Arrays (Unix Only) Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/api-reference/arguments.md On Unix-like systems, Arguments can be created from arrays of raw byte arrays. This is essential for handling non-UTF-8 command-line arguments. ```swift #if !os(Windows) let bytes: [[UInt8]] = [[0x61, 0x62, 0x63], [0x64, 0x65, 0x66]] let args = Arguments(bytes) #endif ``` -------------------------------- ### Executable Locators - By Path Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/README.md Use `Executable.path()` to specify an executable using its absolute or relative file path. ```swift public static func path(_ filePath: FilePath) -> Self ``` -------------------------------- ### Executable Locators - By Name Source: https://github.com/swiftlang/swift-subprocess/blob/main/_autodocs/README.md Use `Executable.name()` to locate an executable by its name in the system's PATH. ```swift public static func name(_ executableName: String) -> Self ```