@@ -26,15 +26,15 @@ This eliminates interim `PipeConfiguration` objects with discarded I/O and makes
26
26
``` swift
27
27
// Using .finally() method
28
28
let config = pipe (
29
- executable : .name (" echo" ),
29
+ .name (" echo" ),
30
30
arguments : [" Hello World" ]
31
31
).finally (
32
32
output : .string (limit : .max )
33
33
)
34
34
35
35
// Using |> operator (visually appealing!)
36
36
let config = pipe (
37
- executable : .name (" echo" ),
37
+ .name (" echo" ),
38
38
arguments : [" Hello World" ]
39
39
) |> .string (limit : .max )
40
40
@@ -47,12 +47,12 @@ print(result.standardOutput) // "Hello World"
47
47
** ✅ Using .finally() method:**
48
48
``` swift
49
49
let pipeline = (pipe (
50
- executable : .name (" echo" ),
50
+ .name (" echo" ),
51
51
arguments : [" apple\n banana\n cherry" ]
52
52
) | .name (" sort" ) // ✅ Builds stage array
53
53
| .name (" head" ) // ✅ Continues building array
54
- | process ( // ✅ Adds configured stage
55
- executable : .name (" wc" ),
54
+ | ( // ✅ Adds configured stage
55
+ .name (" wc" ),
56
56
arguments : [" -l" ]
57
57
)).finally (
58
58
output : .string (limit : .max ), // ✅ Only here we specify real I/O
@@ -63,12 +63,12 @@ let pipeline = (pipe(
63
63
** ✅ Using |> operator (clean and visually appealing!):**
64
64
``` swift
65
65
let pipeline = pipe (
66
- executable : .name (" echo" ),
66
+ .name (" echo" ),
67
67
arguments : [" apple\n banana\n cherry" ]
68
68
) | .name (" sort" ) // ✅ Builds stage array
69
69
| .name (" head" ) // ✅ Continues building array
70
- | process ( // ✅ Adds configured stage
71
- executable : .name (" wc" ),
70
+ | ( // ✅ Adds configured stage
71
+ .name (" wc" ),
72
72
arguments : [" -l" ]
73
73
) |> ( // ✅ Visually appealing final I/O!
74
74
output : .string (limit : .max ),
@@ -86,7 +86,7 @@ PipeConfiguration now supports three modes for handling standard error:
86
86
### ` .separate ` (Default)
87
87
``` swift
88
88
let config = pipe (
89
- executable : .name (" sh" ),
89
+ .name (" sh" ),
90
90
arguments : [" -c" , " echo 'stdout'; echo 'stderr' >&2" ],
91
91
options : .default // or ProcessStageOptions(errorRedirection: .separate)
92
92
) |> (
@@ -102,7 +102,7 @@ let result = try await config.run()
102
102
### ` .replaceStdout ` - Redirect stderr to stdout, discard original stdout
103
103
``` swift
104
104
let config = pipe (
105
- executable : .name (" sh" ),
105
+ .name (" sh" ),
106
106
arguments : [" -c" , " echo 'stdout'; echo 'stderr' >&2" ],
107
107
options : .stderrToStdout // Convenience for .replaceStdout
108
108
) |> (
@@ -118,7 +118,7 @@ let result = try await config.run()
118
118
### ` .mergeWithStdout ` - Both stdout and stderr go to the same destination
119
119
``` swift
120
120
let config = pipe (
121
- executable : .name (" sh" ),
121
+ .name (" sh" ),
122
122
arguments : [" -c" , " echo 'stdout'; echo 'stderr' >&2" ],
123
123
options : .mergeErrors // Convenience for .mergeWithStdout
124
124
) |> (
@@ -136,14 +136,14 @@ let result = try await config.run()
136
136
``` swift
137
137
let pipeline = finally (
138
138
stages : pipe (
139
- executable : .name (" sh" ),
139
+ .name (" sh" ),
140
140
arguments : [" -c" , " echo 'data'; echo 'warning' >&2" ],
141
141
options : .mergeErrors // Merge stderr into stdout
142
142
) | withOptions (
143
143
configuration : Configuration (executable : .name (" grep" ), arguments : [" warning" ]),
144
144
options : .default
145
- ) | process (
146
- executable : .name (" wc" ),
145
+ ) | (
146
+ .name (" wc" ),
147
147
arguments : [" -l" ]
148
148
),
149
149
output : .string (limit : .max ),
@@ -154,18 +154,18 @@ let result = try await pipeline.run()
154
154
// Should find the warning that was merged into stdout
155
155
```
156
156
157
- ### Using ` process() ` helper with options
157
+ ### Using stage options
158
158
``` swift
159
159
let pipeline = finally (
160
160
stages : pipe (
161
- executable : .name (" find" ),
161
+ .name (" find" ),
162
162
arguments : [" /some/path" ]
163
- ) | process (
164
- executable : .name (" grep" ),
163
+ ) | (
164
+ .name (" grep" ),
165
165
arguments : [" -v" , " Permission denied" ],
166
166
options : .stderrToStdout // Convert any stderr to stdout
167
- ) | process (
168
- executable : .name (" wc" ),
167
+ ) | (
168
+ .name (" wc" ),
169
169
arguments : [" -l" ]
170
170
),
171
171
output : .string (limit : .max ),
@@ -177,14 +177,14 @@ let pipeline = finally(
177
177
178
178
### Stage Array Operators (` | ` )
179
179
``` swift
180
- stages | process (.name (" grep" )) // Add simple process stage
180
+ stages | (.name (" grep" )) // Add simple process stage
181
181
stages | Configuration (executable : ... ) // Add configuration stage
182
- stages | process ( // Add with arguments and options
183
- executable : .name (" sort" ),
182
+ stages | ( // Add with arguments and options
183
+ .name (" sort" ),
184
184
arguments : [" -r" ],
185
185
options : .mergeErrors
186
186
)
187
- stages | withOptions ( // Configuration with options
187
+ stages | ( // Configuration with options
188
188
configuration : myConfig,
189
189
options : .stderrToStdout
190
190
)
@@ -209,38 +209,20 @@ finally(stages: myStages, output: .string(limit: .max)) // Auto-discard error
209
209
finally (stages : myStages, input : .string (" data" ), output : .string (limit : .max ), error : .discarded )
210
210
```
211
211
212
- ### ` process() ` - For creating individual process stages
213
- ``` swift
214
- process (executable : .name (" grep" ), arguments : [" pattern" ])
215
- process (executable : .name (" sort" ), arguments : [" -r" ], environment : .inherit )
216
- process (executable : .name (" cat" ), options : .mergeErrors )
217
- process (
218
- executable : .name (" awk" ),
219
- arguments : [" {print $1}" ],
220
- options : .stderrToStdout
221
- )
222
- ```
223
-
224
- ### ` withOptions() ` - For creating Configuration stages with options
225
- ``` swift
226
- withOptions (configuration : myConfig, options : .mergeErrors )
227
- withOptions (configuration : myConfig, options : .stderrToStdout )
228
- ```
229
-
230
212
## Real-World Examples
231
213
232
214
### Log Processing with Error Handling
233
215
``` swift
234
216
let logProcessor = pipe (
235
- executable : .name (" tail" ),
217
+ .name (" tail" ),
236
218
arguments : [" -f" , " /var/log/app.log" ],
237
219
options : .mergeErrors // Capture any tail errors as data
238
- ) | process (
239
- executable : .name (" grep" ),
220
+ ) | (
221
+ .name (" grep" ),
240
222
arguments : [" -E" , " (ERROR|WARN)" ],
241
223
options : .stderrToStdout // Convert grep errors to output
242
224
) |> finally (
243
- executable : .name (" head" ),
225
+ .name (" head" ),
244
226
arguments : [" -20" ],
245
227
output : .string (limit : .max ),
246
228
error : .string (limit : .max ) // Capture final errors separately
@@ -250,15 +232,15 @@ let logProcessor = pipe(
250
232
### File Processing with Error Recovery
251
233
``` swift
252
234
let fileProcessor = pipe (
253
- executable : .name (" find" ),
235
+ .name (" find" ),
254
236
arguments : [" /data" , " -name" , " *.log" , " -type" , " f" ],
255
237
options : .replaceStdout // Convert permission errors to "output"
256
- ) | process (
257
- executable : .name (" head" ),
238
+ ) | (
239
+ .name (" head" ),
258
240
arguments : [" -100" ], // Process first 100 files/errors
259
241
options : .mergeErrors
260
242
) |> finally (
261
- executable : .name (" wc" ),
243
+ .name (" wc" ),
262
244
arguments : [" -l" ],
263
245
output : .string (limit : .max ),
264
246
error : .discarded
@@ -283,10 +265,10 @@ struct OutputData: Codable {
283
265
}
284
266
285
267
let pipeline = pipe (
286
- executable : .name (" echo" ),
268
+ .name (" echo" ),
287
269
arguments : [#" {"items": ["apple", "banana", "cherry"], "metadata": {"source": "test"}}"# ]
288
270
).pipe (
289
- swiftFunction : { input, output, err in
271
+ { input, output, err in
290
272
// Transform JSON structure with type safety
291
273
var jsonData = Data ()
292
274
@@ -331,10 +313,10 @@ struct LogEntry: Codable {
331
313
}
332
314
333
315
let logProcessor = pipe (
334
- executable : .name (" tail" ),
316
+ .name (" tail" ),
335
317
arguments : [" -f" , " /var/log/app.log" ]
336
318
).pipe (
337
- swiftFunction : { input, output, err in
319
+ { input, output, err in
338
320
// Process JSON log entries line by line
339
321
for try await line in input.lines () {
340
322
guard ! line.isEmpty else { continue }
@@ -356,7 +338,7 @@ let logProcessor = pipe(
356
338
return 0
357
339
}
358
340
).pipe (
359
- executable : .name (" head" ),
341
+ .name (" head" ),
360
342
arguments : [" -20" ] // Limit to first 20 error/warning entries
361
343
).finally (
362
344
output : .string (limit : .max ),
@@ -379,10 +361,10 @@ struct SalesSummary: Codable {
379
361
}
380
362
381
363
let salesAnalyzer = pipe (
382
- executable : .name (" cat" ),
364
+ .name (" cat" ),
383
365
arguments : [" sales_data.jsonl" ] // JSON Lines format
384
366
).pipe (
385
- swiftFunction : { input, output, err in
367
+ { input, output, err in
386
368
// Aggregate JSON sales data with Swift collections
387
369
var totalSales: Double = 0
388
370
var productCounts: [String : Int ] = [: ]
@@ -440,10 +422,10 @@ struct User: Codable {
440
422
let usersJson
= #" [{"id": 1, "username": "alice", "email": "[email protected] "}, {"id": 2, "username": "bob", "email": "[email protected] "}, {"id": 3, "username": "charlie", "email": "[email protected] "}, {"id": 6, "username": "dave", "email": "[email protected] "}]"#
441
423
442
424
let userProcessor = pipe (
443
- executable : .name (" echo" ),
425
+ .name (" echo" ),
444
426
arguments : [usersJson]
445
427
).pipe (
446
- swiftFunction : { input, output, err in
428
+ { input, output, err in
447
429
// Decode JSON and filter with Swift
448
430
var jsonData = Data ()
449
431
@@ -467,7 +449,7 @@ let userProcessor = pipe(
467
449
}
468
450
}
469
451
).pipe (
470
- executable : .name (" sort" ) // Use external tool for sorting
452
+ .name (" sort" ) // Use external tool for sorting
471
453
).finally (
472
454
output : .string (limit : .max ),
473
455
error : .string (limit : .max )
@@ -507,49 +489,8 @@ PipeConfiguration<NoInput, StringOutput<UTF8>, DiscardedOutput>
507
489
// Intermediate processes can have different error handling
508
490
// Final process can change output/error types
509
491
pipeline |> finally (
510
- executable : .name (" wc" ),
492
+ .name (" wc" ),
511
493
output : .string (limit : .max ), // New output type
512
494
error : .fileDescriptor (errorFile) // New error type
513
495
) // Result: PipeConfiguration<NoInput, StringOutput<UTF8>, FileDescriptorOutput>
514
496
```
515
-
516
- ## Migration from Old API
517
-
518
- ** ❌ OLD - Repetitive and no error control:**
519
- ``` swift
520
- let oldWay = PipeConfiguration (
521
- executable : .name (" echo" ),
522
- arguments : [" data" ],
523
- input : .none ,
524
- output : .string (limit : .max ), // ❌ misleading - gets replaced
525
- error : .discarded
526
- ).pipe (
527
- executable : .name (" sort" ),
528
- output : .string (limit : .max ) // ❌ misleading - gets replaced
529
- ).pipe (
530
- executable : .name (" head" ),
531
- output : .string (limit : .max ) // ❌ misleading - gets replaced
532
- ).pipe (
533
- executable : .name (" wc" ),
534
- output : .string (limit : .max ) // ✅ only this matters
535
- )
536
- // No control over stderr handling
537
- ```
538
-
539
- ** ✅ NEW - Clear and flexible:**
540
- ``` swift
541
- let newWay = pipe (
542
- executable : .name (" echo" ),
543
- arguments : [" data" ] // ✅ I/O specified at the end
544
- ) | process (
545
- executable : .name (" sort" ),
546
- options : .mergeErrors // ✅ clear error control options
547
- ) | .name (" head" ) // ✅ clear - passing through
548
- |> finally ( // ✅ clear - final output specified here
549
- executable : .name (" wc" ),
550
- output : .string (limit : .max ),
551
- error : .discarded
552
- )
553
- ```
554
-
555
- This design provides a clean, type-safe, and highly flexible API for process pipelines that mirrors familiar shell syntax while providing fine-grained control over error handling that isn't possible in traditional shell pipelines.
0 commit comments