1
1
/*
2
2
This source file is part of the Swift.org open source project
3
-
4
- Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
3
+
4
+ Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
5
5
Licensed under Apache License v2.0 with Runtime Library Exception
6
-
6
+
7
7
See http://swift.org/LICENSE.txt for license information
8
8
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9
9
*/
@@ -92,7 +92,7 @@ public struct ProcessResult: CustomStringConvertible {
92
92
self . stderrOutput = stderrOutput
93
93
self . exitStatus = exitStatus
94
94
}
95
-
95
+
96
96
/// Converts stdout output bytes to string, assuming they're UTF8.
97
97
public func utf8Output( ) throws -> String {
98
98
return String ( decoding: try output. get ( ) , as: Unicode . UTF8. self)
@@ -122,15 +122,15 @@ public final class Process: ObjectIdentifierProtocol {
122
122
/// The program requested to be executed cannot be found on the existing search paths, or is not executable.
123
123
case missingExecutableProgram( program: String )
124
124
}
125
-
125
+
126
126
public enum OutputRedirection {
127
127
/// Do not redirect the output
128
128
case none
129
129
/// Collect stdout and stderr output and provide it back via ProcessResult object
130
130
case collect
131
131
/// Stream stdout and stderr via the corresponding closures
132
132
case stream( stdout: OutputClosure , stderr: OutputClosure )
133
-
133
+
134
134
public var redirectsOutput : Bool {
135
135
switch self {
136
136
case . none:
@@ -139,7 +139,7 @@ public final class Process: ObjectIdentifierProtocol {
139
139
return true
140
140
}
141
141
}
142
-
142
+
143
143
public var outputClosures : ( stdoutClosure: OutputClosure , stderrClosure: OutputClosure ) ? {
144
144
switch self {
145
145
case . stream( let stdoutClosure, let stderrClosure) :
@@ -176,6 +176,9 @@ public final class Process: ObjectIdentifierProtocol {
176
176
/// The environment with which the process was executed.
177
177
public let environment : [ String : String ]
178
178
179
+ /// The path to the directory under which to run the process.
180
+ public let workingDirectory : AbsolutePath ?
181
+
179
182
/// The process id of the spawned process, available after the process is launched.
180
183
#if os(Windows)
181
184
private var _process : Foundation . Process ?
@@ -213,7 +216,7 @@ public final class Process: ObjectIdentifierProtocol {
213
216
/// Queue to protect reading/writing on map of validated executables.
214
217
private static let executablesQueue = DispatchQueue (
215
218
label: " org.swift.swiftpm.process.findExecutable " )
216
-
219
+
217
220
/// Indicates if a new progress group is created for the child process.
218
221
private let startNewProcessGroup : Bool
219
222
@@ -223,6 +226,36 @@ public final class Process: ObjectIdentifierProtocol {
223
226
/// Value: Path to the executable, if found.
224
227
static private var validatedExecutablesMap = [ String: AbsolutePath? ] ( )
225
228
229
+ #if os(macOS)
230
+ /// Create a new process instance.
231
+ ///
232
+ /// - Parameters:
233
+ /// - arguments: The arguments for the subprocess.
234
+ /// - environment: The environment to pass to subprocess. By default the current process environment
235
+ /// will be inherited.
236
+ /// - workingDirectory: The path to the directory under which to run the process.
237
+ /// - outputRedirection: How process redirects its output. Default value is .collect.
238
+ /// - verbose: If true, launch() will print the arguments of the subprocess before launching it.
239
+ /// - startNewProcessGroup: If true, a new progress group is created for the child making it
240
+ /// continue running even if the parent is killed or interrupted. Default value is true.
241
+ @available ( macOS 10 . 15 , * )
242
+ public init (
243
+ arguments: [ String ] ,
244
+ environment: [ String : String ] = ProcessEnv . vars,
245
+ workingDirectory: AbsolutePath ,
246
+ outputRedirection: OutputRedirection = . collect,
247
+ verbose: Bool = Process . verbose,
248
+ startNewProcessGroup: Bool = true
249
+ ) {
250
+ self . arguments = arguments
251
+ self . environment = environment
252
+ self . workingDirectory = workingDirectory
253
+ self . outputRedirection = outputRedirection
254
+ self . verbose = verbose
255
+ self . startNewProcessGroup = startNewProcessGroup
256
+ }
257
+ #endif
258
+
226
259
/// Create a new process instance.
227
260
///
228
261
/// - Parameters:
@@ -242,6 +275,7 @@ public final class Process: ObjectIdentifierProtocol {
242
275
) {
243
276
self . arguments = arguments
244
277
self . environment = environment
278
+ self . workingDirectory = nil
245
279
self . outputRedirection = outputRedirection
246
280
self . verbose = verbose
247
281
self . startNewProcessGroup = startNewProcessGroup
@@ -370,6 +404,17 @@ public final class Process: ObjectIdentifierProtocol {
370
404
posix_spawn_file_actions_init ( & fileActions)
371
405
defer { posix_spawn_file_actions_destroy ( & fileActions) }
372
406
407
+ #if os(macOS)
408
+ if let workingDirectory = workingDirectory? . pathString {
409
+ // The only way to set a workingDirectory is using an availability-gated initializer, so we don't need
410
+ // to handle the case where the posix_spawn_file_actions_addchdir_np method is unavailable. This check only
411
+ // exists here to make the compiler happy.
412
+ if #available( macOS 10 . 15 , * ) {
413
+ posix_spawn_file_actions_addchdir_np ( & fileActions, workingDirectory)
414
+ }
415
+ }
416
+ #endif
417
+
373
418
// Workaround for https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=89e435f3559c53084498e9baad22172b64429362
374
419
// Change allowing for newer version of glibc
375
420
guard let devNull = strdup ( " /dev/null " ) else {
@@ -408,7 +453,7 @@ public final class Process: ObjectIdentifierProtocol {
408
453
409
454
if outputRedirection. redirectsOutput {
410
455
let outputClosures = outputRedirection. outputClosures
411
-
456
+
412
457
// Close the write end of the output pipe.
413
458
try close ( fd: & outputPipe[ 1 ] )
414
459
@@ -682,7 +727,7 @@ extension ProcessResult.Error: CustomStringConvertible {
682
727
stream <<< " \n "
683
728
}
684
729
}
685
-
730
+
686
731
return stream. bytes. description
687
732
}
688
733
}
0 commit comments