+build_essential = ["build-essential"]
+
+#---------- output handling
+#
+# There are at least the following kinds of output:
+#
+# 1. stderr output which consists of
+# 1a. our errors
+# 1b. stuff printed to stderr by the virtualisation server
+# 1c. stuff printed to stderr by our short-lived subprocesseses
+# which we don't expect to fail
+#
+# 2. trace information, which consists of
+# 2a. our trace information from calls to debug()
+# 2b. progress information and stderr output from
+# general scripts we run on the host
+# 2c. progress information and stderr output from things
+# we run on the testbed including builds
+# 2d. stderr and stdout output from actual tests
+#
+# xxxx
+# 3. actual test results (printed to our stdout)
+#
+# Cloning of 1a and 2a, where necessary, is done by us writing
+# the data twice. Cloning of 1[bc] and 2[bc], where necessary,
+# is done by forking off a copy of ourselves to do plumbing,
+# which copy we wait for at the appropriate point.
+
+class DummyOpts:
+ def __init__(do): do.debuglevel = 0
+
+opts = DummyOpts()
+trace_stream = None
+summary_stream = None
+
+def pstderr(m):
+ print >>sys.stderr, m
+ if trace_stream is not None: print >>trace_stream, m
+
+def debug(m, minlevel=0):
+ if opts.debuglevel < minlevel: return
+ if opts.quiet and trace_stream is None: return
+ p = 'adt-run: trace'
+ if minlevel: p += `minlevel`
+ p += ': '
+ for l in m.rstrip('\n').split('\n'):
+ s = p + l
+ if not opts.quiet: print >>sys.stderr, s
+ if trace_stream is not None: print >>trace_stream, s
+
+def debug_file(hp, minlevel=0):
+ if opts.debuglevel < minlevel: return
+ def do_copy(stream, what):
+ rc = subprocess.call(['cat',hp], stdout=stream)
+ if rc: bomb('cat failed copying data from %s'
+ ' to %s, exit code %d' % (hp, what, rc))
+ if not opts.quiet: do_copy(sys.stderr, 'stderr')
+ if trace_stream is not None: do_copy(trace_stream, 'trace log')
+
+class Errplumb:
+ def __init__(ep, critical=False):
+ to_stderr = critical or not opts.quiet
+ count = to_stderr + (trace_stream is not None)
+ if count == 0:
+ ep.stream = open('/dev/null','w')
+ ep._sp = None
+ elif count == 1:
+ if to_stderr: ep.stream = os.dup(2)
+ else: ep.stream = trace_stream
+ ep._sp = None
+ else:
+ ep._sp = subprocess.Popen(['tee','-a','/dev/stderr'],
+ stdin=subprocess.PIPE, stdout=trace_stream,
+ close_fds=True)
+ ep.stream = ep._sp.stdin
+ def wait(ep):
+ if ep._sp is None: return
+ if type(ep.stream) == type(2):
+ os.close(ep.stream)
+ ep.stream = ()
+ ep._sp.stdin.close()
+ rc = ep._sp.wait()
+ if rc: bomb('stderr plumbing tee(1) failed, exit code %d' % rc)
+ ep._sp = None
+
+def subprocess_cooked(cmdl, critical=False, dbg=None, **kwargs):
+ if dbg is not None:
+ if isinstance(dbg,tuple): (what,script) = dbg
+ else: (what,script) = (dbg,None)
+ debug_subprocess(what, cmdl, script=script)
+ ep = Errplumb(critical)
+ running = subprocess.Popen(cmdl, stderr=ep.stream, **kwargs)
+ output = running.communicate()[0]
+ rc = running.wait()
+ ep.wait()
+ return (rc, output)
+
+def psummary(m):
+ if summary_stream is not None: print >>summary_stream, m
+
+def preport(m):
+ print m
+ sys.stdout.flush()
+ if trace_stream is not None: print >>trace_stream, m
+ psummary(m)
+
+def report(tname, result):
+ preport('%-20s %s' % (tname, result))