Advertisement
Guest User

runner.py

a guest
May 29th, 2021
923
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.25 KB | None | 0 0
  1. import argparse
  2. import asyncio
  3. import io
  4. import pathlib
  5. import shlex
  6. import sys
  7. from asyncio.subprocess import PIPE
  8.  
  9.  
  10. class PrefixedStream(io.IOBase):
  11. def __init__(self, stream, prefix):
  12. self.stream = stream
  13. self.prefix = prefix
  14. self.flush = stream.flush
  15.  
  16. def close(self):
  17. pass
  18.  
  19. def write(self, b):
  20. return self.stream.write(self.prefix + b)
  21.  
  22.  
  23. async def tee(in_stream, out_streams):
  24. line = await in_stream.readline()
  25. while line.endswith(b"\n"):
  26. for out_stream in out_streams:
  27. out_stream.write(line)
  28. if hasattr(out_stream, "flush"):
  29. out_stream.flush()
  30. line = await in_stream.readline()
  31.  
  32. if line:
  33. for out_stream in out_streams:
  34. out_stream.write(line)
  35. if hasattr(out_stream, "flush"):
  36. out_stream.flush()
  37.  
  38. for out_stream in out_streams:
  39. out_stream.close()
  40.  
  41.  
  42. async def show_exit_code(process, prefix):
  43. print(prefix, await process.wait(), sep="")
  44.  
  45.  
  46. async def async_main(argv=None):
  47. argv = sys.argv if argv is None else argv
  48.  
  49. parser = argparse.ArgumentParser(pathlib.Path(argv[0]).name, description="A interactive runner")
  50. parser.add_argument("command_1", type=str, help="command to execute first program")
  51. parser.add_argument("command_2", type=str, help="Command to execute second program")
  52. parser.add_argument(
  53. "--command1-stdout-prefix",
  54. metavar="PREFIX",
  55. default="Command 1 (stdout): ",
  56. help="Prefix to add before the first command's stdout",
  57. )
  58. parser.add_argument(
  59. "--command1-stderr-prefix",
  60. metavar="PREFIX",
  61. default="Command 1 (stderr): ",
  62. help="Prefix to add before the first command's stderr",
  63. )
  64. parser.add_argument(
  65. "--command2-stdout-prefix",
  66. metavar="PREFIX",
  67. default="Command 2 (stdout): ",
  68. help="Prefix to add before the second command's stdout",
  69. )
  70. parser.add_argument(
  71. "--command2-stderr-prefix",
  72. metavar="PREFIX",
  73. default="Command 2 (stderr): ",
  74. help="Prefix to add before the second command's stderr",
  75. )
  76.  
  77. args = parser.parse_args(argv[1:])
  78.  
  79. proc_1 = await asyncio.create_subprocess_exec(*shlex.split(args.command_1), stdin=PIPE, stdout=PIPE, stderr=PIPE)
  80. proc_2 = await asyncio.create_subprocess_exec(*shlex.split(args.command_2), stdin=PIPE, stdout=PIPE, stderr=PIPE)
  81.  
  82. proc_1_stdout = PrefixedStream(sys.stdout.buffer, args.command1_stdout_prefix.encode("utf-8"))
  83. proc_2_stdout = PrefixedStream(sys.stdout.buffer, args.command2_stdout_prefix.encode("utf-8"))
  84. proc_1_stderr = PrefixedStream(sys.stderr.buffer, args.command1_stderr_prefix.encode("utf-8"))
  85. proc_2_stderr = PrefixedStream(sys.stderr.buffer, args.command2_stderr_prefix.encode("utf-8"))
  86.  
  87. await asyncio.gather(
  88. tee(proc_1.stdout, [proc_2.stdin, proc_1_stdout]),
  89. tee(proc_2.stdout, [proc_1.stdin, proc_2_stdout]),
  90. tee(proc_1.stderr, [proc_1_stderr]),
  91. tee(proc_2.stderr, [proc_2_stderr]),
  92. )
  93.  
  94.  
  95. def main(argv=None):
  96. argv = sys.argv if argv is None else argv
  97. asyncio.run(async_main(argv))
  98.  
  99.  
  100. if __name__ == "__main__":
  101. main()
  102.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement