blob: c1c228ecf9a58dce43f41e145d2a42ac976a61ab [file] [log] [blame]
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Module for running cbuildbot stages in the background."""
import multiprocessing
import os
import Queue
import sys
import tempfile
import traceback
from chromite.buildbot import cbuildbot_stages as stages
_PRINT_INTERVAL = 1
class BackgroundStages(multiprocessing.Process):
"""Run a list of stages in sequence in the background."""
def __init__(self):
multiprocessing.Process.__init__(self)
self._stages = []
self._files = []
self._queue = multiprocessing.Queue()
def AddStage(self, stage):
"""Add a stage to the list of stages to run in the background."""
output = tempfile.NamedTemporaryFile(delete=False)
self._stages.append((stage, output))
def WaitForStage(self):
"""Wait for the first stage to complete.
Return whether an exception was caught."""
assert not self.Empty()
stage, output = self._stages.pop(0)
pos = 0
more_output = True
while more_output:
# Check whether the process is finished.
try:
error, results = self._queue.get(True, _PRINT_INTERVAL)
more_output = False
except Queue.Empty:
more_output = True
# Print output so far.
output.seek(pos)
for line in output:
sys.stdout.write(line)
pos = output.tell()
output.close()
os.unlink(output.name)
for result in results:
stages.Results.Record(*result)
return error
def Empty(self):
"""Return True if there are any stages left to run."""
return len(self._stages) == 0
def run(self):
"""Run the list of stages."""
# Be nice so that foreground processes get CPU if they need it.
os.nice(10)
stdout_fileno = sys.stdout.fileno()
stderr_fileno = sys.stderr.fileno()
for stage, output in self._stages:
# Send all output to a named temporary file.
os.dup2(output.fileno(), stdout_fileno)
os.dup2(output.fileno(), stderr_fileno)
error = True
try:
stages.Results.Clear()
stage.Run()
error = False
except:
traceback.print_exc(file=output)
output.close()
results = stages.Results.Get()
self._queue.put((error, results))