OILS / win32 / demo_asyncio.py View on Github | oils.pub

91 lines, 51 significant
1#!/usr/bin/env python3
2"""
3Testing child process APIs on Windows
4"""
5
6import asyncio
7import sys
8import os
9from typing import List
10
11
12async def run_pipeline_async(commands: List[List[str]]) -> List[int]:
13 """Run a pipeline of commands, letting stdout flow naturally, and return exit codes."""
14 if not commands:
15 return []
16
17 exit_codes = []
18 stdin = None # Initial stdin is None (inherited)
19
20 # Create pipes for connecting processes
21 processes = []
22
23 # Set up all processes in the pipeline
24 for i, cmd in enumerate(commands):
25 # For all processes except the last one, create a pipe for stdout
26 if i < len(commands) - 1:
27 # Create a pipe for this process's stdout to the next process's stdin
28 read_fd, write_fd = os.pipe()
29 stdout = write_fd
30 next_stdin = read_fd
31 else:
32 # Last process inherits stdout (terminal or parent process stdout)
33 stdout = None
34 next_stdin = None
35
36 # Create the process
37 proc = await asyncio.create_subprocess_exec(
38 *cmd,
39 stdin=stdin,
40 stdout=stdout,
41 stderr=None # Inherit stderr
42 )
43
44 processes.append(proc)
45
46 # Close write end of pipe in parent process after spawning child
47 if i < len(commands) - 1:
48 os.close(write_fd)
49
50 # Set up for next iteration
51 stdin = next_stdin
52
53 # Wait for all processes to complete and collect exit codes
54 for proc in processes:
55 await proc.wait()
56 exit_codes.append(proc.returncode)
57
58 return exit_codes
59
60
61def RunPipeline(*commands) -> List[int]:
62 """Run a pipeline of commands with natural output flow and return exit codes."""
63 return asyncio.run(run_pipeline_async(commands))
64
65
66def SubprocessDemo():
67 if sys.platform == 'win32':
68 a_list = [['dir', 'build'], ['find', 'sh'], ['find', 'o']]
69
70 a_list2 = []
71 for a in a_list:
72 a_list2.append(['cmd.exe', '/c'] + a)
73 print(a_list2)
74
75 #codes = RunPipeline(a_list2[0], a_list2[1], a_list2[2])
76 exit_codes = RunPipeline(*a_list2)
77 print(f"Exit codes: {exit_codes}")
78 return
79
80 # ls build | grep sh | wc -l
81 exit_codes = RunPipeline(['ls', 'build'], ['grep', 'sh'], ['grep', 'o'])
82 print(f"Exit codes: {exit_codes}")
83
84 exit_codes = RunPipeline(['ls', 'build'], ['sh', '-c', 'grep py; exit 42'],
85 ['wc', '-l'])
86 print(f"Exit codes: {exit_codes}")
87
88
89# Example usage
90if __name__ == "__main__":
91 SubprocessDemo()