summaryrefslogtreecommitdiffstats
path: root/testing/legion/process.py
diff options
context:
space:
mode:
authormmeade <mmeade@chromium.org>2015-08-11 08:51:26 -0700
committerCommit bot <commit-bot@chromium.org>2015-08-11 15:52:12 +0000
commitd27d249b3a56061cb7d27a4b36a87c283ff90bb3 (patch)
tree5101c66e5356c01a04822214dcb2a38fc4fc3c31 /testing/legion/process.py
parent3d2ab39099e766ac5eee5e151a980d4023de1758 (diff)
downloadchromium_src-d27d249b3a56061cb7d27a4b36a87c283ff90bb3.zip
chromium_src-d27d249b3a56061cb7d27a4b36a87c283ff90bb3.tar.gz
chromium_src-d27d249b3a56061cb7d27a4b36a87c283ff90bb3.tar.bz2
Fixing some issues when on Windows.
The sleep and ls commands aren't supported on Windows. I changed them to use python from the command line to implement a cross-OS version of these. I also added some additional features to better support running processes remotely. BUG= Review URL: https://codereview.chromium.org/1267743005 Cr-Commit-Position: refs/heads/master@{#342824}
Diffstat (limited to 'testing/legion/process.py')
-rw-r--r--testing/legion/process.py46
1 files changed, 38 insertions, 8 deletions
diff --git a/testing/legion/process.py b/testing/legion/process.py
index f3cabb5..b013c11 100644
--- a/testing/legion/process.py
+++ b/testing/legion/process.py
@@ -13,6 +13,7 @@ import os
import subprocess
import sys
import threading
+import time
#pylint: disable=relative-import
import common_lib
@@ -23,6 +24,10 @@ sys.path.append(common_lib.SWARMING_DIR)
from utils import subprocess42
+class TimeoutError(Exception):
+ pass
+
+
class ControllerProcessWrapper(object):
"""Controller-side process wrapper class.
@@ -31,7 +36,7 @@ class ControllerProcessWrapper(object):
"""
def __init__(self, rpc, cmd, verbose=False, detached=False, cwd=None,
- key=None):
+ key=None, shell=None):
logging.info('Creating a process with cmd=%s', cmd)
self._rpc = rpc
self._key = rpc.subprocess.Process(cmd, key)
@@ -41,7 +46,9 @@ class ControllerProcessWrapper(object):
if detached:
self._rpc.subprocess.SetDetached(self._key)
if cwd:
- self._rpc.subprocess.SetCwd(self._rpc, cwd)
+ self._rpc.subprocess.SetCwd(self._key, cwd)
+ if shell:
+ self._rpc.subprocess.SetShell(self._key)
self._rpc.subprocess.Start(self._key)
@property
@@ -86,8 +93,8 @@ class ControllerProcessWrapper(object):
"""
return self._rpc.subprocess.ReadOutput(self._key)
- def Wait(self):
- return self._rpc.subprocess.Wait(self._key)
+ def Wait(self, timeout=None):
+ return self._rpc.subprocess.Wait(self._key, timeout)
def Poll(self):
return self._rpc.subprocess.Poll(self._key)
@@ -96,7 +103,6 @@ class ControllerProcessWrapper(object):
return self._rpc.subprocess.GetPid(self._key)
-
class Process(object):
"""Implements a task-side non-blocking subprocess.
@@ -120,8 +126,10 @@ class Process(object):
self.cmd = cmd
self.proc = None
self.cwd = None
+ self.shell = False
self.verbose = False
self.detached = False
+ self.complete = False
self.data_lock = threading.Lock()
self.stdout_file = open(self._CreateOutputFilename('stdout'), 'wb+')
self.stderr_file = open(self._CreateOutputFilename('stderr'), 'wb+')
@@ -148,6 +156,7 @@ class Process(object):
self.stderr_file.flush()
if self.verbose:
sys.stderr.write(data)
+ self.complete = True
@classmethod
def KillAll(cls):
@@ -170,7 +179,8 @@ class Process(object):
logging.info('Starting process %s', self)
self.proc = subprocess42.Popen(self.cmd, stdout=subprocess42.PIPE,
stderr=subprocess42.PIPE,
- detached=self.detached, cwd=self.cwd)
+ detached=self.detached, cwd=self.cwd,
+ shell=self.shell)
threading.Thread(target=self._reader).start()
@classmethod
@@ -184,6 +194,12 @@ class Process(object):
cls._processes[key].cwd = cwd
@classmethod
+ def SetShell(cls, key):
+ """Sets the process's shell arg to True."""
+ logging.debug('Setting %s.shell = True', key)
+ cls._processes[key].shell = True
+
+ @classmethod
def SetDetached(cls, key):
"""Creates a detached process."""
logging.debug('Setting %s.detached = True', key)
@@ -255,8 +271,22 @@ class Process(object):
return cls.ReadStdout(key), cls.ReadStderr(key)
@classmethod
- def Wait(cls, key):
- return cls._processes[key].proc.wait()
+ def Wait(cls, key, timeout=None):
+ """Wait for the process to complete.
+
+ We wait for all of the output to be written before returning. This solves
+ a race condition found on Windows where the output can lag behind the
+ wait call.
+
+ Raises:
+ TimeoutError if the process doesn't finish in the specified timeout.
+ """
+ end = None if timeout is None else timeout + time.time()
+ while end is None or end > time.time():
+ if cls._processes[key].complete:
+ return
+ time.sleep(0.05)
+ raise TimeoutError()
@classmethod
def Poll(cls, key):