@@ -23,6 +23,59 @@ 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
+ get {
62
+ return storage [ Key ( key) ]
63
+ }
64
+ set {
65
+ storage [ Key ( key) ] = newValue
66
+ }
67
+ }
68
+
69
+ public subscript( _ key: String , default value: String ) -> String {
70
+ return storage [ Key ( key) , default: value]
71
+ }
72
+
73
+ public func contains( _ key: String ) -> Bool {
74
+ return storage. keys. contains ( Key ( key) )
75
+ }
76
+ }
77
+
78
+
26
79
/// Process result data which is available after process termination.
27
80
public struct ProcessResult : CustomStringConvertible , Sendable {
28
81
@@ -53,7 +106,7 @@ public struct ProcessResult: CustomStringConvertible, Sendable {
53
106
public let arguments : [ String ]
54
107
55
108
/// The environment with which the process was launched.
56
- public let environment : [ String : String ]
109
+ public let environment : ProcessEnvironmentBlock
57
110
58
111
/// The exit status of the process.
59
112
public let exitStatus : ExitStatus
@@ -71,7 +124,7 @@ public struct ProcessResult: CustomStringConvertible, Sendable {
71
124
/// See `waitpid(2)` for information on the exit status code.
72
125
public init (
73
126
arguments: [ String ] ,
74
- environment: [ String : String ] ,
127
+ environment: ProcessEnvironmentBlock ,
75
128
exitStatusCode: Int32 ,
76
129
normal: Bool ,
77
130
output: Result < [ UInt8 ] , Swift . Error > ,
@@ -99,7 +152,7 @@ public struct ProcessResult: CustomStringConvertible, Sendable {
99
152
/// Create an instance using an exit status and output result.
100
153
public init (
101
154
arguments: [ String ] ,
102
- environment: [ String : String ] ,
155
+ environment: ProcessEnvironmentBlock ,
103
156
exitStatus: ExitStatus ,
104
157
output: Result < [ UInt8 ] , Swift . Error > ,
105
158
stderrOutput: Result < [ UInt8 ] , Swift . Error >
@@ -285,7 +338,7 @@ public final class Process {
285
338
public let arguments : [ String ]
286
339
287
340
/// The environment with which the process was executed.
288
- public let environment : [ String : String ]
341
+ public let environment : ProcessEnvironmentBlock
289
342
290
343
/// The path to the directory under which to run the process.
291
344
public let workingDirectory : AbsolutePath ?
@@ -359,7 +412,7 @@ public final class Process {
359
412
@available ( macOS 10 . 15 , * )
360
413
public init (
361
414
arguments: [ String ] ,
362
- environment: [ String : String ] = ProcessEnv . vars,
415
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
363
416
workingDirectory: AbsolutePath ,
364
417
outputRedirection: OutputRedirection = . collect,
365
418
startNewProcessGroup: Bool = true ,
@@ -379,7 +432,7 @@ public final class Process {
379
432
@available ( macOS 10 . 15 , * )
380
433
public convenience init (
381
434
arguments: [ String ] ,
382
- environment: [ String : String ] = ProcessEnv . vars,
435
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
383
436
workingDirectory: AbsolutePath ,
384
437
outputRedirection: OutputRedirection = . collect,
385
438
verbose: Bool ,
@@ -411,7 +464,7 @@ public final class Process {
411
464
/// - loggingHandler: Handler for logging messages
412
465
public init (
413
466
arguments: [ String ] ,
414
- environment: [ String : String ] = ProcessEnv . vars,
467
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
415
468
outputRedirection: OutputRedirection = . collect,
416
469
startNewProcessGroup: Bool = true ,
417
470
loggingHandler: LoggingHandler ? = . none
@@ -428,7 +481,7 @@ public final class Process {
428
481
@available ( * , deprecated, message: " use version without verbosity flag " )
429
482
public convenience init (
430
483
arguments: [ String ] ,
431
- environment: [ String : String ] = ProcessEnv . vars,
484
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
432
485
outputRedirection: OutputRedirection = . collect,
433
486
verbose: Bool = Process . verbose,
434
487
startNewProcessGroup: Bool = true
@@ -444,7 +497,7 @@ public final class Process {
444
497
445
498
public convenience init (
446
499
args: String ... ,
447
- environment: [ String : String ] = ProcessEnv . vars,
500
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
448
501
outputRedirection: OutputRedirection = . collect,
449
502
loggingHandler: LoggingHandler ? = . none
450
503
) {
@@ -536,7 +589,7 @@ public final class Process {
536
589
process. currentDirectoryURL = workingDirectory. asURL
537
590
}
538
591
process. executableURL = executablePath. asURL
539
- process. environment = environment
592
+ process. environment = environment. dictionary
540
593
541
594
let stdinPipe = Pipe ( )
542
595
process. standardInput = stdinPipe
@@ -989,7 +1042,7 @@ extension Process {
989
1042
@available ( macOS 10 . 15 , iOS 13 . 0 , tvOS 13 . 0 , watchOS 6 . 0 , * )
990
1043
static public func popen(
991
1044
arguments: [ String ] ,
992
- environment: [ String : String ] = ProcessEnv . vars,
1045
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
993
1046
loggingHandler: LoggingHandler ? = . none
994
1047
) async throws -> ProcessResult {
995
1048
let process = Process (
@@ -1012,7 +1065,7 @@ extension Process {
1012
1065
@available ( macOS 10 . 15 , iOS 13 . 0 , tvOS 13 . 0 , watchOS 6 . 0 , * )
1013
1066
static public func popen(
1014
1067
args: String ... ,
1015
- environment: [ String : String ] = ProcessEnv . vars,
1068
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1016
1069
loggingHandler: LoggingHandler ? = . none
1017
1070
) async throws -> ProcessResult {
1018
1071
try await popen ( arguments: args, environment: environment, loggingHandler: loggingHandler)
@@ -1030,7 +1083,7 @@ extension Process {
1030
1083
@discardableResult
1031
1084
static public func checkNonZeroExit(
1032
1085
arguments: [ String ] ,
1033
- environment: [ String : String ] = ProcessEnv . vars,
1086
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1034
1087
loggingHandler: LoggingHandler ? = . none
1035
1088
) async throws -> String {
1036
1089
let result = try await popen ( arguments: arguments, environment: environment, loggingHandler: loggingHandler)
@@ -1053,7 +1106,7 @@ extension Process {
1053
1106
@discardableResult
1054
1107
static public func checkNonZeroExit(
1055
1108
args: String ... ,
1056
- environment: [ String : String ] = ProcessEnv . vars,
1109
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1057
1110
loggingHandler: LoggingHandler ? = . none
1058
1111
) async throws -> String {
1059
1112
try await checkNonZeroExit ( arguments: args, environment: environment, loggingHandler: loggingHandler)
@@ -1075,7 +1128,7 @@ extension Process {
1075
1128
// #endif
1076
1129
static public func popen(
1077
1130
arguments: [ String ] ,
1078
- environment: [ String : String ] = ProcessEnv . vars,
1131
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1079
1132
loggingHandler: LoggingHandler ? = . none,
1080
1133
queue: DispatchQueue ? = nil ,
1081
1134
completion: @escaping ( Result < ProcessResult , Swift . Error > ) -> Void
@@ -1113,7 +1166,7 @@ extension Process {
1113
1166
@discardableResult
1114
1167
static public func popen(
1115
1168
arguments: [ String ] ,
1116
- environment: [ String : String ] = ProcessEnv . vars,
1169
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1117
1170
loggingHandler: LoggingHandler ? = . none
1118
1171
) throws -> ProcessResult {
1119
1172
let process = Process (
@@ -1140,7 +1193,7 @@ extension Process {
1140
1193
@discardableResult
1141
1194
static public func popen(
1142
1195
args: String ... ,
1143
- environment: [ String : String ] = ProcessEnv . vars,
1196
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1144
1197
loggingHandler: LoggingHandler ? = . none
1145
1198
) throws -> ProcessResult {
1146
1199
return try Process . popen ( arguments: args, environment: environment, loggingHandler: loggingHandler)
@@ -1160,7 +1213,7 @@ extension Process {
1160
1213
@discardableResult
1161
1214
static public func checkNonZeroExit(
1162
1215
arguments: [ String ] ,
1163
- environment: [ String : String ] = ProcessEnv . vars,
1216
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1164
1217
loggingHandler: LoggingHandler ? = . none
1165
1218
) throws -> String {
1166
1219
let process = Process (
@@ -1192,7 +1245,7 @@ extension Process {
1192
1245
@discardableResult
1193
1246
static public func checkNonZeroExit(
1194
1247
args: String ... ,
1195
- environment: [ String : String ] = ProcessEnv . vars,
1248
+ environment: ProcessEnvironmentBlock = ProcessEnv . vars,
1196
1249
loggingHandler: LoggingHandler ? = . none
1197
1250
) throws -> String {
1198
1251
return try checkNonZeroExit ( arguments: args, environment: environment, loggingHandler: loggingHandler)
0 commit comments