#!/usr/bin/python3.12
# Copyright 2017-2018 Francesco Riosa <vivo75+smalltools@gmail.com>
# Distributed under the terms of the GNU General Public License v2

import signal
import sys
# This block ensures that ^C interrupts are handled quietly.
try:
	def exithandler(signum, _frame):
		signal.signal(signal.SIGINT, signal.SIG_IGN)
		signal.signal(signal.SIGTERM, signal.SIG_IGN)
		sys.exit(128 + signum)

	signal.signal(signal.SIGINT, exithandler)
	signal.signal(signal.SIGTERM, exithandler)

except KeyboardInterrupt:
	sys.exit(128 + signal.SIGINT)

import os
import time
import subprocess
import argparse
from concurrent.futures import ThreadPoolExecutor


class writer:
	f = None
	ondisk = False

	def __init__(self, filename, append):
		mode = "w"
		if filename is not None:
			self.ondisk = True
			if append:
				mode = "a"
			self.f = open(filename, mode)

	def out(self, msg):
		print(msg, end='')
		if self.ondisk:
			self.f.write(msg)

def main():
	def pipe_consumer(seq, pipe):
		if pipe.readable:
			line = pipe.readline()
		else:
			line = None
		while prog.poll() is None or line not in (None, ""):
			if line != "":
				w.out("[{0:d},{1:.9f}] {2}".format(seq, time.monotonic(), line))
				a=True
			line = pipe.readline()

	def stdout_consumer():
		pipe_consumer(1, prog.stdout)

	def stderr_consumer():
		pipe_consumer(2, prog.stderr)

	argv = sys.argv

	selfname = os.path.basename(argv[0])

	parser = argparse.ArgumentParser(description='mix std{out,err}')

	parser.add_argument('-t', '--tee', dest='filename',
						help='duplicate output to file')
	parser.add_argument('-a', '--append', dest='append', action='store_true',
						help='append (rather than create) output file')
	parser.add_argument('command', nargs=argparse.REMAINDER)

	args = parser.parse_args(argv[1:])

	w = writer(args.filename, args.append)

	w.out("{}:exec:'{}'\n".format(selfname, args.command))

	if w.ondisk:
		w.out("{}:log:'{}'\n".format(selfname, os.path.realpath(args.filename)))

	prog = subprocess.Popen(
		args.command,
		stdout = subprocess.PIPE,
		stderr = subprocess.PIPE,
		bufsize = 0,
		universal_newlines = False,
		errors = 'backslashreplace',
		)

	executor = ThreadPoolExecutor(max_workers=2)
	so = executor.submit(stdout_consumer)
	se = executor.submit(stderr_consumer)

	# wait for the children program to stop
	prog.wait()
	# and for the threads to flush all data
	while so.running() or se.running():
		time.sleep(0.05)

	w.out("{}:retcode:{}\n".format(selfname, prog.returncode))
	return prog.returncode

if __name__ == '__main__':
	sys.exit(main())

# vim:fileencoding=utf-8
# kate: syntax Python; encoding utf-8; eol unix; indent-pasted-text false;
# kate: tab-width 4; indent-width 4; show-tabs true; keep-extra-spaces false;
# kate: remove-trailing-space on; word-wrap-column 120; line-numbers true;
