@@ -26,15 +26,15 @@ This eliminates interim `PipeConfiguration` objects with discarded I/O and makes
2626``` swift
2727// Using .finally() method
2828let config = pipe (
29- executable : .name (" echo" ),
29+ .name (" echo" ),
3030 arguments : [" Hello World" ]
3131).finally (
3232 output : .string (limit : .max )
3333)
3434
3535// Using |> operator (visually appealing!)
3636let config = pipe (
37- executable : .name (" echo" ),
37+ .name (" echo" ),
3838 arguments : [" Hello World" ]
3939) |> .string (limit : .max )
4040
@@ -47,12 +47,12 @@ print(result.standardOutput) // "Hello World"
4747** ✅ Using .finally() method:**
4848``` swift
4949let pipeline = (pipe (
50- executable : .name (" echo" ),
50+ .name (" echo" ),
5151 arguments : [" apple\n banana\n cherry" ]
5252) | .name (" sort" ) // ✅ Builds stage array
5353 | .name (" head" ) // ✅ Continues building array
54- | process ( // ✅ Adds configured stage
55- executable : .name (" wc" ),
54+ | ( // ✅ Adds configured stage
55+ .name (" wc" ),
5656 arguments : [" -l" ]
5757 )).finally (
5858 output : .string (limit : .max ), // ✅ Only here we specify real I/O
@@ -63,12 +63,12 @@ let pipeline = (pipe(
6363** ✅ Using |> operator (clean and visually appealing!):**
6464``` swift
6565let pipeline = pipe (
66- executable : .name (" echo" ),
66+ .name (" echo" ),
6767 arguments : [" apple\n banana\n cherry" ]
6868) | .name (" sort" ) // ✅ Builds stage array
6969 | .name (" head" ) // ✅ Continues building array
70- | process ( // ✅ Adds configured stage
71- executable : .name (" wc" ),
70+ | ( // ✅ Adds configured stage
71+ .name (" wc" ),
7272 arguments : [" -l" ]
7373 ) |> ( // ✅ Visually appealing final I/O!
7474 output : .string (limit : .max ),
@@ -86,7 +86,7 @@ PipeConfiguration now supports three modes for handling standard error:
8686### ` .separate ` (Default)
8787``` swift
8888let config = pipe (
89- executable : .name (" sh" ),
89+ .name (" sh" ),
9090 arguments : [" -c" , " echo 'stdout'; echo 'stderr' >&2" ],
9191 options : .default // or ProcessStageOptions(errorRedirection: .separate)
9292) |> (
@@ -102,7 +102,7 @@ let result = try await config.run()
102102### ` .replaceStdout ` - Redirect stderr to stdout, discard original stdout
103103``` swift
104104let config = pipe (
105- executable : .name (" sh" ),
105+ .name (" sh" ),
106106 arguments : [" -c" , " echo 'stdout'; echo 'stderr' >&2" ],
107107 options : .stderrToStdout // Convenience for .replaceStdout
108108) |> (
@@ -118,7 +118,7 @@ let result = try await config.run()
118118### ` .mergeWithStdout ` - Both stdout and stderr go to the same destination
119119``` swift
120120let config = pipe (
121- executable : .name (" sh" ),
121+ .name (" sh" ),
122122 arguments : [" -c" , " echo 'stdout'; echo 'stderr' >&2" ],
123123 options : .mergeErrors // Convenience for .mergeWithStdout
124124) |> (
@@ -136,14 +136,14 @@ let result = try await config.run()
136136``` swift
137137let pipeline = finally (
138138 stages : pipe (
139- executable : .name (" sh" ),
139+ .name (" sh" ),
140140 arguments : [" -c" , " echo 'data'; echo 'warning' >&2" ],
141141 options : .mergeErrors // Merge stderr into stdout
142142 ) | withOptions (
143143 configuration : Configuration (executable : .name (" grep" ), arguments : [" warning" ]),
144144 options : .default
145- ) | process (
146- executable : .name (" wc" ),
145+ ) | (
146+ .name (" wc" ),
147147 arguments : [" -l" ]
148148 ),
149149 output : .string (limit : .max ),
@@ -154,18 +154,18 @@ let result = try await pipeline.run()
154154// Should find the warning that was merged into stdout
155155```
156156
157- ### Using ` process() ` helper with options
157+ ### Using stage options
158158``` swift
159159let pipeline = finally (
160160 stages : pipe (
161- executable : .name (" find" ),
161+ .name (" find" ),
162162 arguments : [" /some/path" ]
163- ) | process (
164- executable : .name (" grep" ),
163+ ) | (
164+ .name (" grep" ),
165165 arguments : [" -v" , " Permission denied" ],
166166 options : .stderrToStdout // Convert any stderr to stdout
167- ) | process (
168- executable : .name (" wc" ),
167+ ) | (
168+ .name (" wc" ),
169169 arguments : [" -l" ]
170170 ),
171171 output : .string (limit : .max ),
@@ -177,14 +177,14 @@ let pipeline = finally(
177177
178178### Stage Array Operators (` | ` )
179179``` swift
180- stages | process (.name (" grep" )) // Add simple process stage
180+ stages | (.name (" grep" )) // Add simple process stage
181181stages | 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" ),
184184 arguments : [" -r" ],
185185 options : .mergeErrors
186186)
187- stages | withOptions ( // Configuration with options
187+ stages | ( // Configuration with options
188188 configuration : myConfig,
189189 options : .stderrToStdout
190190)
@@ -209,38 +209,20 @@ finally(stages: myStages, output: .string(limit: .max)) // Auto-discard error
209209finally (stages : myStages, input : .string (" data" ), output : .string (limit : .max ), error : .discarded )
210210```
211211
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-
230212## Real-World Examples
231213
232214### Log Processing with Error Handling
233215``` swift
234216let logProcessor = pipe (
235- executable : .name (" tail" ),
217+ .name (" tail" ),
236218 arguments : [" -f" , " /var/log/app.log" ],
237219 options : .mergeErrors // Capture any tail errors as data
238- ) | process (
239- executable : .name (" grep" ),
220+ ) | (
221+ .name (" grep" ),
240222 arguments : [" -E" , " (ERROR|WARN)" ],
241223 options : .stderrToStdout // Convert grep errors to output
242224) |> finally (
243- executable : .name (" head" ),
225+ .name (" head" ),
244226 arguments : [" -20" ],
245227 output : .string (limit : .max ),
246228 error : .string (limit : .max ) // Capture final errors separately
@@ -250,15 +232,15 @@ let logProcessor = pipe(
250232### File Processing with Error Recovery
251233``` swift
252234let fileProcessor = pipe (
253- executable : .name (" find" ),
235+ .name (" find" ),
254236 arguments : [" /data" , " -name" , " *.log" , " -type" , " f" ],
255237 options : .replaceStdout // Convert permission errors to "output"
256- ) | process (
257- executable : .name (" head" ),
238+ ) | (
239+ .name (" head" ),
258240 arguments : [" -100" ], // Process first 100 files/errors
259241 options : .mergeErrors
260242) |> finally (
261- executable : .name (" wc" ),
243+ .name (" wc" ),
262244 arguments : [" -l" ],
263245 output : .string (limit : .max ),
264246 error : .discarded
@@ -283,10 +265,10 @@ struct OutputData: Codable {
283265}
284266
285267let pipeline = pipe (
286- executable : .name (" echo" ),
268+ .name (" echo" ),
287269 arguments : [#" {"items": ["apple", "banana", "cherry"], "metadata": {"source": "test"}}"# ]
288270).pipe (
289- swiftFunction : { input, output, err in
271+ { input, output, err in
290272 // Transform JSON structure with type safety
291273 var jsonData = Data ()
292274
@@ -331,10 +313,10 @@ struct LogEntry: Codable {
331313}
332314
333315let logProcessor = pipe (
334- executable : .name (" tail" ),
316+ .name (" tail" ),
335317 arguments : [" -f" , " /var/log/app.log" ]
336318).pipe (
337- swiftFunction : { input, output, err in
319+ { input, output, err in
338320 // Process JSON log entries line by line
339321 for try await line in input.lines () {
340322 guard ! line.isEmpty else { continue }
@@ -356,7 +338,7 @@ let logProcessor = pipe(
356338 return 0
357339 }
358340).pipe (
359- executable : .name (" head" ),
341+ .name (" head" ),
360342 arguments : [" -20" ] // Limit to first 20 error/warning entries
361343).finally (
362344 output : .string (limit : .max ),
@@ -379,10 +361,10 @@ struct SalesSummary: Codable {
379361}
380362
381363let salesAnalyzer = pipe (
382- executable : .name (" cat" ),
364+ .name (" cat" ),
383365 arguments : [" sales_data.jsonl" ] // JSON Lines format
384366).pipe (
385- swiftFunction : { input, output, err in
367+ { input, output, err in
386368 // Aggregate JSON sales data with Swift collections
387369 var totalSales: Double = 0
388370 var productCounts: [String : Int ] = [: ]
@@ -440,10 +422,10 @@ struct User: Codable {
440422let 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] "}]"# 441423
442424let userProcessor = pipe (
443- executable : .name (" echo" ),
425+ .name (" echo" ),
444426 arguments : [usersJson]
445427).pipe (
446- swiftFunction : { input, output, err in
428+ { input, output, err in
447429 // Decode JSON and filter with Swift
448430 var jsonData = Data ()
449431
@@ -467,7 +449,7 @@ let userProcessor = pipe(
467449 }
468450 }
469451).pipe (
470- executable : .name (" sort" ) // Use external tool for sorting
452+ .name (" sort" ) // Use external tool for sorting
471453).finally (
472454 output : .string (limit : .max ),
473455 error : .string (limit : .max )
@@ -507,49 +489,8 @@ PipeConfiguration<NoInput, StringOutput<UTF8>, DiscardedOutput>
507489// Intermediate processes can have different error handling
508490// Final process can change output/error types
509491pipeline |> finally (
510- executable : .name (" wc" ),
492+ .name (" wc" ),
511493 output : .string (limit : .max ), // New output type
512494 error : .fileDescriptor (errorFile) // New error type
513495) // Result: PipeConfiguration<NoInput, StringOutput<UTF8>, FileDescriptorOutput>
514496```
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