1#! /usr/bin/env python
2# encoding: utf-8
3# Thomas Nagy, 2016-2018 (ita)
4
5import os, sys, traceback, base64, signal
6try:
7	import cPickle
8except ImportError:
9	import pickle as cPickle
10
11try:
12	import subprocess32 as subprocess
13except ImportError:
14	import subprocess
15
16try:
17	TimeoutExpired = subprocess.TimeoutExpired
18except AttributeError:
19	class TimeoutExpired(Exception):
20		pass
21
22def run():
23	txt = sys.stdin.readline().strip()
24	if not txt:
25		# parent process probably ended
26		sys.exit(1)
27	[cmd, kwargs, cargs] = cPickle.loads(base64.b64decode(txt))
28	cargs = cargs or {}
29
30	if not 'close_fds' in kwargs:
31		# workers have no fds
32		kwargs['close_fds'] = False
33
34	ret = 1
35	out, err, ex, trace = (None, None, None, None)
36	try:
37		proc = subprocess.Popen(cmd, **kwargs)
38		try:
39			out, err = proc.communicate(**cargs)
40		except TimeoutExpired:
41			if kwargs.get('start_new_session') and hasattr(os, 'killpg'):
42				os.killpg(proc.pid, signal.SIGKILL)
43			else:
44				proc.kill()
45			out, err = proc.communicate()
46			exc = TimeoutExpired(proc.args, timeout=cargs['timeout'], output=out)
47			exc.stderr = err
48			raise exc
49		ret = proc.returncode
50	except Exception as e:
51		exc_type, exc_value, tb = sys.exc_info()
52		exc_lines = traceback.format_exception(exc_type, exc_value, tb)
53		trace = str(cmd) + '\n' + ''.join(exc_lines)
54		ex = e.__class__.__name__
55
56	# it is just text so maybe we do not need to pickle()
57	tmp = [ret, out, err, ex, trace]
58	obj = base64.b64encode(cPickle.dumps(tmp))
59	sys.stdout.write(obj.decode())
60	sys.stdout.write('\n')
61	sys.stdout.flush()
62
63while 1:
64	try:
65		run()
66	except KeyboardInterrupt:
67		break
68
69