@@ -23,6 +23,50 @@ 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
+
69
+
26
70
/// Process result data which is available after process termination.
27
71
public struct ProcessResult : CustomStringConvertible , Sendable {
28
72
@@ -53,7 +97,7 @@ public struct ProcessResult: CustomStringConvertible, Sendable {
53
97
public let arguments : [ String ]
54
98
55
99
/// The environment with which the process was launched.
56
- public let environment : [ String : String ]
100
+ public let environment : ProcessEnvironmentBlock
57
101
58
102
/// The exit status of the process.
59
103
public let exitStatus : ExitStatus
@@ -71,7 +115,7 @@ public struct ProcessResult: CustomStringConvertible, Sendable {
71
115
/// See `waitpid(2)` for information on the exit status code.
72
116
public init (
73
117
arguments: [ String ] ,
74
- environment: [ String : String ] ,
118
+ environment: ProcessEnvironmentBlock ,
75
119
exitStatusCode: Int32 ,
76
120
normal: Bool ,
77
121
output: Result < [ UInt8 ] , Swift . Error > ,
@@ -99,7 +143,7 @@ public struct ProcessResult: CustomStringConvertible, Sendable {
99
143
/// Create an instance using an exit status and output result.
100
144
public init (
101
145
arguments: [ String ] ,
102
- environment: [ String : String ] ,
146
+ environment: ProcessEnvironmentBlock ,
103
147
exitStatus: ExitStatus ,
104
148
output: Result < [ UInt8 ] , Swift . Error > ,
105
149
stderrOutput: Result < [ UInt8 ] , Swift . Error >
@@ -285,7 +329,7 @@ public final class Process {
285
329
public let arguments : [ String ]
286
330
287
331
/// The environment with which the process was executed.
288
- public let environment : [ String : String ]
332
+ public let environment : ProcessEnvironmentBlock
289
333
290
334
/// The path to the directory under which to run the process.
291
335
public let workingDirectory : AbsolutePath ?
@@ -359,7 +403,7 @@ public final class Process {
359
403
@available ( macOS 10 . 15 , * )
360
404
public init (
361
405
arguments: [ String ] ,
362
- environment: [ String : String ] = ProcessEnv . vars,
406
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
363
407
workingDirectory: AbsolutePath ,
364
408
outputRedirection: OutputRedirection = . collect,
365
409
startNewProcessGroup: Bool = true ,
@@ -379,7 +423,7 @@ public final class Process {
379
423
@available ( macOS 10 . 15 , * )
380
424
public convenience init (
381
425
arguments: [ String ] ,
382
- environment: [ String : String ] = ProcessEnv . vars,
426
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
383
427
workingDirectory: AbsolutePath ,
384
428
outputRedirection: OutputRedirection = . collect,
385
429
verbose: Bool ,
@@ -411,7 +455,7 @@ public final class Process {
411
455
/// - loggingHandler: Handler for logging messages
412
456
public init (
413
457
arguments: [ String ] ,
414
- environment: [ String : String ] = ProcessEnv . vars,
458
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
415
459
outputRedirection: OutputRedirection = . collect,
416
460
startNewProcessGroup: Bool = true ,
417
461
loggingHandler: LoggingHandler ? = . none
@@ -428,7 +472,7 @@ public final class Process {
428
472
@available ( * , deprecated, message: " use version without verbosity flag " )
429
473
public convenience init (
430
474
arguments: [ String ] ,
431
- environment: [ String : String ] = ProcessEnv . vars,
475
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
432
476
outputRedirection: OutputRedirection = . collect,
433
477
verbose: Bool = Process . verbose,
434
478
startNewProcessGroup: Bool = true
@@ -444,7 +488,7 @@ public final class Process {
444
488
445
489
public convenience init (
446
490
args: String ... ,
447
- environment: [ String : String ] = ProcessEnv . vars,
491
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
448
492
outputRedirection: OutputRedirection = . collect,
449
493
loggingHandler: LoggingHandler ? = . none
450
494
) {
@@ -536,7 +580,7 @@ public final class Process {
536
580
process. currentDirectoryURL = workingDirectory. asURL
537
581
}
538
582
process. executableURL = executablePath. asURL
539
- process. environment = environment
583
+ process. environment = environment. dictionary
540
584
541
585
let stdinPipe = Pipe ( )
542
586
process. standardInput = stdinPipe
@@ -989,7 +1033,7 @@ extension Process {
989
1033
@available ( macOS 10 . 15 , iOS 13 . 0 , tvOS 13 . 0 , watchOS 6 . 0 , * )
990
1034
static public func popen(
991
1035
arguments: [ String ] ,
992
- environment: [ String : String ] = ProcessEnv . vars,
1036
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
993
1037
loggingHandler: LoggingHandler ? = . none
994
1038
) async throws -> ProcessResult {
995
1039
let process = Process (
@@ -1012,7 +1056,7 @@ extension Process {
1012
1056
@available ( macOS 10 . 15 , iOS 13 . 0 , tvOS 13 . 0 , watchOS 6 . 0 , * )
1013
1057
static public func popen(
1014
1058
args: String ... ,
1015
- environment: [ String : String ] = ProcessEnv . vars,
1059
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1016
1060
loggingHandler: LoggingHandler ? = . none
1017
1061
) async throws -> ProcessResult {
1018
1062
try await popen ( arguments: args, environment: environment, loggingHandler: loggingHandler)
@@ -1030,7 +1074,7 @@ extension Process {
1030
1074
@discardableResult
1031
1075
static public func checkNonZeroExit(
1032
1076
arguments: [ String ] ,
1033
- environment: [ String : String ] = ProcessEnv . vars,
1077
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1034
1078
loggingHandler: LoggingHandler ? = . none
1035
1079
) async throws -> String {
1036
1080
let result = try await popen ( arguments: arguments, environment: environment, loggingHandler: loggingHandler)
@@ -1053,7 +1097,7 @@ extension Process {
1053
1097
@discardableResult
1054
1098
static public func checkNonZeroExit(
1055
1099
args: String ... ,
1056
- environment: [ String : String ] = ProcessEnv . vars,
1100
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1057
1101
loggingHandler: LoggingHandler ? = . none
1058
1102
) async throws -> String {
1059
1103
try await checkNonZeroExit ( arguments: args, environment: environment, loggingHandler: loggingHandler)
@@ -1075,7 +1119,7 @@ extension Process {
1075
1119
// #endif
1076
1120
static public func popen(
1077
1121
arguments: [ String ] ,
1078
- environment: [ String : String ] = ProcessEnv . vars,
1122
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1079
1123
loggingHandler: LoggingHandler ? = . none,
1080
1124
queue: DispatchQueue ? = nil ,
1081
1125
completion: @escaping ( Result < ProcessResult , Swift . Error > ) -> Void
@@ -1113,7 +1157,7 @@ extension Process {
1113
1157
@discardableResult
1114
1158
static public func popen(
1115
1159
arguments: [ String ] ,
1116
- environment: [ String : String ] = ProcessEnv . vars,
1160
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1117
1161
loggingHandler: LoggingHandler ? = . none
1118
1162
) throws -> ProcessResult {
1119
1163
let process = Process (
@@ -1140,7 +1184,7 @@ extension Process {
1140
1184
@discardableResult
1141
1185
static public func popen(
1142
1186
args: String ... ,
1143
- environment: [ String : String ] = ProcessEnv . vars,
1187
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1144
1188
loggingHandler: LoggingHandler ? = . none
1145
1189
) throws -> ProcessResult {
1146
1190
return try Process . popen ( arguments: args, environment: environment, loggingHandler: loggingHandler)
@@ -1160,7 +1204,7 @@ extension Process {
1160
1204
@discardableResult
1161
1205
static public func checkNonZeroExit(
1162
1206
arguments: [ String ] ,
1163
- environment: [ String : String ] = ProcessEnv . vars,
1207
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1164
1208
loggingHandler: LoggingHandler ? = . none
1165
1209
) throws -> String {
1166
1210
let process = Process (
@@ -1192,7 +1236,7 @@ extension Process {
1192
1236
@discardableResult
1193
1237
static public func checkNonZeroExit(
1194
1238
args: String ... ,
1195
- environment: [ String : String ] = ProcessEnv . vars,
1239
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1196
1240
loggingHandler: LoggingHandler ? = . none
1197
1241
) throws -> String {
1198
1242
return try checkNonZeroExit ( arguments: args, environment: environment, loggingHandler: loggingHandler)
0 commit comments