blob: 5336f332d750aaec1d2fa6a5c492503a95971325 [file] [log] [blame]
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -08001#!/usr/bin/python2.4
2#
3#
4# Copyright 2007, The Android Open Source Project
5#
Nicolas Catania97b24c42009-04-22 11:08:32 -07006# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -08009#
Nicolas Catania97b24c42009-04-22 11:08:32 -070010# http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080011#
Nicolas Catania97b24c42009-04-22 11:08:32 -070012# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080016# limitations under the License.
17
18# System imports
19import os
20import signal
21import subprocess
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080022import threading
Nicolas Catania97b24c42009-04-22 11:08:32 -070023import time
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080024
25# local imports
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080026import errors
Nicolas Catania97b24c42009-04-22 11:08:32 -070027import logger
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080028
29_abort_on_error = False
30
31def SetAbortOnError(abort=True):
Nicolas Catania97b24c42009-04-22 11:08:32 -070032 """Sets behavior of RunCommand to throw AbortError if command process returns
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080033 a negative error code"""
34 global _abort_on_error
35 _abort_on_error = abort
Nicolas Catania97b24c42009-04-22 11:08:32 -070036
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080037def RunCommand(cmd, timeout_time=None, retry_count=3, return_output=True):
38 """Spawns a subprocess to run the given shell command, and checks for
39 timeout_time. If return_output is True, the output of the command is returned
40 as a string. Otherwise, output of command directed to stdout """
41
42 result = None
43 while True:
44 try:
Nicolas Catania97b24c42009-04-22 11:08:32 -070045 result = RunOnce(cmd, timeout_time=timeout_time,
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080046 return_output=return_output)
47 except errors.WaitForResponseTimedOutError:
48 if retry_count == 0:
49 raise
50 retry_count -= 1
51 logger.Log("No response for %s, retrying" % cmd)
52 else:
53 # Success
54 return result
55
56def RunOnce(cmd, timeout_time=None, return_output=True):
57 start_time = time.time()
58 so = []
59 pid = []
60 global _abort_on_error
61 error_occurred = False
Nicolas Catania97b24c42009-04-22 11:08:32 -070062
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080063 def Run():
64 if return_output:
65 output_dest = subprocess.PIPE
66 else:
67 # None means direct to stdout
Nicolas Catania97b24c42009-04-22 11:08:32 -070068 output_dest = None
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080069 pipe = subprocess.Popen(
70 cmd,
71 executable='/bin/bash',
72 stdout=output_dest,
73 stderr=subprocess.STDOUT,
74 shell=True)
75 pid.append(pipe.pid)
76 try:
77 output = pipe.communicate()[0]
78 if output is not None and len(output) > 0:
79 so.append(output)
80 except OSError, e:
81 logger.SilentLog("failed to retrieve stdout from: %s" % cmd)
82 logger.Log(e)
83 so.append("ERROR")
84 error_occurred = True
85 if pipe.returncode < 0:
Nicolas Catania97b24c42009-04-22 11:08:32 -070086 logger.SilentLog("Error: %s was terminated by signal %d" %(cmd,
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080087 pipe.returncode))
Nicolas Catania97b24c42009-04-22 11:08:32 -070088 error_occurred = True
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080089
90 t = threading.Thread(target=Run)
91 t.start()
92
93 break_loop = False
94 while not break_loop:
95 if not t.isAlive():
96 break_loop = True
97
98 # Check the timeout
99 if (not break_loop and timeout_time is not None
100 and time.time() > start_time + timeout_time):
101 try:
102 os.kill(pid[0], signal.SIGKILL)
103 except OSError:
104 # process already dead. No action required.
105 pass
106
107 logger.SilentLog("about to raise a timeout for: %s" % cmd)
108 raise errors.WaitForResponseTimedOutError
109 if not break_loop:
110 time.sleep(0.1)
111
112 t.join()
113
114 if _abort_on_error and error_occurred:
115 raise errors.AbortError
Nicolas Catania97b24c42009-04-22 11:08:32 -0700116
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800117 return "".join(so)
Nicolas Catania97b24c42009-04-22 11:08:32 -0700118
119
120def RunHostCommand(binary, valgrind=False):
121 """Run a command on the host (opt using valgrind).
122
123 Runs the host binary. Does not capture any output but it
124 returns the exit code. The command can be run under valgrind.
125
126 Args:
127 binary: basename of the file to be run. It is expected to be under
128 out/host/linux-x86/bin.
129 valgrind: If True the command will be run under valgrind.
130
131 Returns:
132 The command exit code (int)
133 """
134 full_path = os.path.join("out", "host", "linux-x86", "bin", binary)
135 if not valgrind:
136 return subprocess.call(full_path)
137 else:
138 return subprocess.call(["/usr/bin/valgrind", "-q", full_path])