Cloned from CL 57424 by 'g4 patch'.
Original change by raymes@raymes-crosstool-git5-11blah-git5 on 2011/12/14 11:43:10.

-Added the failure reason of jobs to the text report.
-Added some logging about cache hit/misses.
-Allowed checksums to be computed simultaneously
-Renamed action_runner to experiment_runner
-Moved storing results logic to experiment_runner
-Improvements to logging

Added the following fixes:
-Don't store run results when Ctrl-C is pressed in the middle of a run.
-Refactor caching code a bit to make it clearer.
-Fixed exception thrown when the cache was empty.
-Changed profile_type to be "" when it is invalid instead of "none".
-Fixed exception when using cache if no profile is present in the cache
file.
-Made ExecuteCommandInChroot() thread- and process-safe.

Added a DIFFBASE= for convenience.

PRESUBMIT=passed
R=raymes,bjanakiraman,shenhan
DELTA=412  (163 added, 183 deleted, 66 changed)
OCL=57454-p2
RCL=57583-p2
RDATE=2011/12/27 14:17:33
DIFFBASE=57424-p2


P4 change: 42662702
diff --git a/v14/utils/utils.py b/v14/utils/utils.py
index a6f1553..d82b243 100755
--- a/v14/utils/utils.py
+++ b/v14/utils/utils.py
@@ -12,6 +12,7 @@
 import stat
 import command_executer
 import logger
+import tempfile
 from contextlib import contextmanager
 
 
@@ -67,17 +68,26 @@
   return "./setup_board --board=%s %s" % (board, " ".join(options))
 
 
-def ExecuteCommandInChroot(chromeos_root, command, return_output=False):
+def ExecuteCommandInChroot(chromeos_root, command, return_output=False,
+                           command_terminator=None):
   ce = command_executer.GetCommandExecuter()
-  command_file = "in_chroot_cmd.sh"
-  command_file_path = os.path.join(chromeos_root, "src/scripts", command_file)
-  with open(command_file_path, "w") as f:
+  handle, command_file = tempfile.mkstemp(dir=os.path.join(chromeos_root,
+                                                           "src/scripts"),
+                                          suffix=".sh",
+                                          prefix="in_chroot_cmd")
+  # Without this, the handle remains open and we get "file busy" when executing
+  # cros_sdk -- ./<file>.
+  os.close(handle)
+  with open(command_file, "w") as f:
     print >> f, "#!/bin/bash"
     print >> f, command
-  os.chmod(command_file_path, 0777)
+  os.chmod(command_file, 0777)
   with WorkingDirectory(chromeos_root):
-    command = "cros_sdk -- ./%s" % command_file
-    return ce.RunCommand(command, return_output)
+    command = "cros_sdk -- ./%s" % os.path.basename(command_file)
+    ret = ce.RunCommand(command, return_output,
+                        command_terminator=command_terminator)
+    os.remove(command_file)
+    return ret
 
 
 def CanonicalizePath(path):
@@ -111,4 +121,3 @@
     msg = "cd %s" % old_dir
     logger.GetLogger().LogCmd(msg)
   os.chdir(old_dir)
-