@@ -23,6 +23,54 @@ import Dispatch
23
23
24
24
import _Concurrency
25
25
26
+ public struct ProcessEnvironmentBlock {
27
+ #if os(Windows)
28
+ internal typealias Key = CaseInsensitiveString
29
+ #else
30
+ internal typealias Key = String
31
+ #endif
32
+
33
+ private var storage : Dictionary < Key , String >
34
+
35
+ public init ( dictionary: Dictionary < String , String > ) {
36
+ #if os(Windows)
37
+ self . storage = . init( uniqueKeysWithValues: dictionary. map {
38
+ ( CaseInsensitiveString ( $0) , $1)
39
+ } )
40
+ #else
41
+ self . storage = dictionary
42
+ #endif
43
+ }
44
+
45
+ internal init < S: Sequence > ( uniqueKeysWithValues keysAndValues: S )
46
+ where S. Element == ( Key , String ) {
47
+ storage = . init( uniqueKeysWithValues: keysAndValues)
48
+ }
49
+
50
+ public var dictionary : Dictionary < String , String > {
51
+ #if os(Windows)
52
+ return Dictionary < String , String > ( uniqueKeysWithValues: storage. map {
53
+ ( $0. value, $1)
54
+ } )
55
+ #else
56
+ return storage
57
+ #endif
58
+ }
59
+
60
+ public subscript( _ key: String ) -> String ? {
61
+ #if os(Windows)
62
+ return storage [ CaseInsensitiveString ( key) ]
63
+ #else
64
+ return storage [ key]
65
+ #endif
66
+ }
67
+
68
+ public func contains( _ key: String ) -> Bool {
69
+ return storage. keys. contains ( Key ( key) )
70
+ }
71
+ }
72
+
73
+
26
74
/// Process result data which is available after process termination.
27
75
public struct ProcessResult : CustomStringConvertible , Sendable {
28
76
@@ -53,7 +101,7 @@ public struct ProcessResult: CustomStringConvertible, Sendable {
53
101
public let arguments : [ String ]
54
102
55
103
/// The environment with which the process was launched.
56
- public let environment : [ String : String ]
104
+ public let environment : ProcessEnvironmentBlock
57
105
58
106
/// The exit status of the process.
59
107
public let exitStatus : ExitStatus
@@ -71,7 +119,7 @@ public struct ProcessResult: CustomStringConvertible, Sendable {
71
119
/// See `waitpid(2)` for information on the exit status code.
72
120
public init (
73
121
arguments: [ String ] ,
74
- environment: [ String : String ] ,
122
+ environment: ProcessEnvironmentBlock ,
75
123
exitStatusCode: Int32 ,
76
124
normal: Bool ,
77
125
output: Result < [ UInt8 ] , Swift . Error > ,
@@ -99,7 +147,7 @@ public struct ProcessResult: CustomStringConvertible, Sendable {
99
147
/// Create an instance using an exit status and output result.
100
148
public init (
101
149
arguments: [ String ] ,
102
- environment: [ String : String ] ,
150
+ environment: ProcessEnvironmentBlock ,
103
151
exitStatus: ExitStatus ,
104
152
output: Result < [ UInt8 ] , Swift . Error > ,
105
153
stderrOutput: Result < [ UInt8 ] , Swift . Error >
@@ -285,7 +333,7 @@ public final class Process {
285
333
public let arguments : [ String ]
286
334
287
335
/// The environment with which the process was executed.
288
- public let environment : [ String : String ]
336
+ public let environment : ProcessEnvironmentBlock
289
337
290
338
/// The path to the directory under which to run the process.
291
339
public let workingDirectory : AbsolutePath ?
@@ -359,7 +407,7 @@ public final class Process {
359
407
@available ( macOS 10 . 15 , * )
360
408
public init (
361
409
arguments: [ String ] ,
362
- environment: [ String : String ] = ProcessEnv . vars,
410
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
363
411
workingDirectory: AbsolutePath ,
364
412
outputRedirection: OutputRedirection = . collect,
365
413
startNewProcessGroup: Bool = true ,
@@ -379,7 +427,7 @@ public final class Process {
379
427
@available ( macOS 10 . 15 , * )
380
428
public convenience init (
381
429
arguments: [ String ] ,
382
- environment: [ String : String ] = ProcessEnv . vars,
430
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
383
431
workingDirectory: AbsolutePath ,
384
432
outputRedirection: OutputRedirection = . collect,
385
433
verbose: Bool ,
@@ -411,7 +459,7 @@ public final class Process {
411
459
/// - loggingHandler: Handler for logging messages
412
460
public init (
413
461
arguments: [ String ] ,
414
- environment: [ String : String ] = ProcessEnv . vars,
462
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
415
463
outputRedirection: OutputRedirection = . collect,
416
464
startNewProcessGroup: Bool = true ,
417
465
loggingHandler: LoggingHandler ? = . none
@@ -428,7 +476,7 @@ public final class Process {
428
476
@available ( * , deprecated, message: " use version without verbosity flag " )
429
477
public convenience init (
430
478
arguments: [ String ] ,
431
- environment: [ String : String ] = ProcessEnv . vars,
479
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
432
480
outputRedirection: OutputRedirection = . collect,
433
481
verbose: Bool = Process . verbose,
434
482
startNewProcessGroup: Bool = true
@@ -444,7 +492,7 @@ public final class Process {
444
492
445
493
public convenience init (
446
494
args: String ... ,
447
- environment: [ String : String ] = ProcessEnv . vars,
495
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
448
496
outputRedirection: OutputRedirection = . collect,
449
497
loggingHandler: LoggingHandler ? = . none
450
498
) {
@@ -536,7 +584,7 @@ public final class Process {
536
584
process. currentDirectoryURL = workingDirectory. asURL
537
585
}
538
586
process. executableURL = executablePath. asURL
539
- process. environment = environment
587
+ process. environment = environment. dictionary
540
588
541
589
let stdinPipe = Pipe ( )
542
590
process. standardInput = stdinPipe
@@ -989,7 +1037,7 @@ extension Process {
989
1037
@available ( macOS 10 . 15 , iOS 13 . 0 , tvOS 13 . 0 , watchOS 6 . 0 , * )
990
1038
static public func popen(
991
1039
arguments: [ String ] ,
992
- environment: [ String : String ] = ProcessEnv . vars,
1040
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
993
1041
loggingHandler: LoggingHandler ? = . none
994
1042
) async throws -> ProcessResult {
995
1043
let process = Process (
@@ -1012,7 +1060,7 @@ extension Process {
1012
1060
@available ( macOS 10 . 15 , iOS 13 . 0 , tvOS 13 . 0 , watchOS 6 . 0 , * )
1013
1061
static public func popen(
1014
1062
args: String ... ,
1015
- environment: [ String : String ] = ProcessEnv . vars,
1063
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1016
1064
loggingHandler: LoggingHandler ? = . none
1017
1065
) async throws -> ProcessResult {
1018
1066
try await popen ( arguments: args, environment: environment, loggingHandler: loggingHandler)
@@ -1030,7 +1078,7 @@ extension Process {
1030
1078
@discardableResult
1031
1079
static public func checkNonZeroExit(
1032
1080
arguments: [ String ] ,
1033
- environment: [ String : String ] = ProcessEnv . vars,
1081
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1034
1082
loggingHandler: LoggingHandler ? = . none
1035
1083
) async throws -> String {
1036
1084
let result = try await popen ( arguments: arguments, environment: environment, loggingHandler: loggingHandler)
@@ -1053,7 +1101,7 @@ extension Process {
1053
1101
@discardableResult
1054
1102
static public func checkNonZeroExit(
1055
1103
args: String ... ,
1056
- environment: [ String : String ] = ProcessEnv . vars,
1104
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1057
1105
loggingHandler: LoggingHandler ? = . none
1058
1106
) async throws -> String {
1059
1107
try await checkNonZeroExit ( arguments: args, environment: environment, loggingHandler: loggingHandler)
@@ -1075,7 +1123,7 @@ extension Process {
1075
1123
// #endif
1076
1124
static public func popen(
1077
1125
arguments: [ String ] ,
1078
- environment: [ String : String ] = ProcessEnv . vars,
1126
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1079
1127
loggingHandler: LoggingHandler ? = . none,
1080
1128
queue: DispatchQueue ? = nil ,
1081
1129
completion: @escaping ( Result < ProcessResult , Swift . Error > ) -> Void
@@ -1113,7 +1161,7 @@ extension Process {
1113
1161
@discardableResult
1114
1162
static public func popen(
1115
1163
arguments: [ String ] ,
1116
- environment: [ String : String ] = ProcessEnv . vars,
1164
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1117
1165
loggingHandler: LoggingHandler ? = . none
1118
1166
) throws -> ProcessResult {
1119
1167
let process = Process (
@@ -1140,7 +1188,7 @@ extension Process {
1140
1188
@discardableResult
1141
1189
static public func popen(
1142
1190
args: String ... ,
1143
- environment: [ String : String ] = ProcessEnv . vars,
1191
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1144
1192
loggingHandler: LoggingHandler ? = . none
1145
1193
) throws -> ProcessResult {
1146
1194
return try Process . popen ( arguments: args, environment: environment, loggingHandler: loggingHandler)
@@ -1160,7 +1208,7 @@ extension Process {
1160
1208
@discardableResult
1161
1209
static public func checkNonZeroExit(
1162
1210
arguments: [ String ] ,
1163
- environment: [ String : String ] = ProcessEnv . vars,
1211
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1164
1212
loggingHandler: LoggingHandler ? = . none
1165
1213
) throws -> String {
1166
1214
let process = Process (
@@ -1192,7 +1240,7 @@ extension Process {
1192
1240
@discardableResult
1193
1241
static public func checkNonZeroExit(
1194
1242
args: String ... ,
1195
- environment: [ String : String ] = ProcessEnv . vars,
1243
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1196
1244
loggingHandler: LoggingHandler ? = . none
1197
1245
) throws -> String {
1198
1246
return try checkNonZeroExit ( arguments: args, environment: environment, loggingHandler: loggingHandler)
0 commit comments