Various cosmetic improvements to run_tests.py

  -) Adding a new command line flag to be able to see which tests are passing.
  -) Adding more status when the tool is idle in forever mode.
  -) Adding a last status when the tool is finished so to avoid leaving the console in a weird state.
  -) Adding a status message in the forever mode if the previous run failed.
  -) Swapped the message and its explanation, so you don't have to scroll up to see which test failed.
  -) Fixed a race condition in the watch_dir.py code if a file is deleted during the loop.
diff --git a/tools/run_tests/jobset.py b/tools/run_tests/jobset.py
index 17fb1d6..0214e95 100755
--- a/tools/run_tests/jobset.py
+++ b/tools/run_tests/jobset.py
@@ -40,9 +40,11 @@
 
 
 _COLORS = {
-    'red': 31,
-    'green': 32,
-    'yellow': 33,
+    'red': [ 31, 0 ],
+    'green': [ 32, 0 ],
+    'yellow': [ 33, 0 ],
+    'lightgray': [ 37, 0],
+    'gray': [ 30, 1 ],
     }
 
 
@@ -53,32 +55,37 @@
 _TAG_COLOR = {
     'FAILED': 'red',
     'PASSED': 'green',
-    'START': 'yellow',
+    'START': 'gray',
     'WAITING': 'yellow',
+    'SUCCESS': 'green',
+    'IDLE': 'gray',
     }
 
 
-def message(tag, message, explanatory_text=None):
-  sys.stdout.write('%s%s\x1b[%dm%s\x1b[0m: %s%s' % (
+def message(tag, message, explanatory_text=None, do_newline=False):
+  sys.stdout.write('%s%s%s\x1b[%d;%dm%s\x1b[0m: %s%s' % (
       _BEGINNING_OF_LINE,
       _CLEAR_LINE,
-      _COLORS[_TAG_COLOR[tag]],
+      '\n%s' % explanatory_text if explanatory_text is not None else '',
+      _COLORS[_TAG_COLOR[tag]][1],
+      _COLORS[_TAG_COLOR[tag]][0],
       tag,
       message,
-      '\n%s\n' % explanatory_text if explanatory_text is not None else ''))
+      '\n' if do_newline or explanatory_text is not None else ''))
   sys.stdout.flush()
 
 
 class Job(object):
   """Manages one job."""
 
-  def __init__(self, cmdline):
+  def __init__(self, cmdline, newline_on_success):
     self._cmdline = ' '.join(cmdline)
     self._tempfile = tempfile.TemporaryFile()
     self._process = subprocess.Popen(args=cmdline,
                                      stderr=subprocess.STDOUT,
                                      stdout=self._tempfile)
     self._state = _RUNNING
+    self._newline_on_success = newline_on_success
     message('START', self._cmdline)
 
   def state(self):
@@ -91,7 +98,7 @@
         message('FAILED', '%s [ret=%d]' % (self._cmdline, self._process.returncode), stdout)
       else:
         self._state = _SUCCESS
-        message('PASSED', '%s' % self._cmdline)
+        message('PASSED', '%s' % self._cmdline, do_newline=self._newline_on_success)
     return self._state
 
   def kill(self):
@@ -103,13 +110,14 @@
 class Jobset(object):
   """Manages one run of jobs."""
 
-  def __init__(self, check_cancelled, maxjobs):
+  def __init__(self, check_cancelled, maxjobs, newline_on_success):
     self._running = set()
     self._check_cancelled = check_cancelled
     self._cancelled = False
     self._failures = 0
     self._completed = 0
     self._maxjobs = maxjobs
+    self._newline_on_success = newline_on_success
 
   def start(self, cmdline):
     """Start a job. Return True on success, False on failure."""
@@ -117,7 +125,7 @@
       if self.cancelled(): return False
       self.reap()
     if self.cancelled(): return False
-    self._running.add(Job(cmdline))
+    self._running.add(Job(cmdline, self._newline_on_success))
     return True
 
   def reap(self):
@@ -157,9 +165,10 @@
   return False
 
 
-def run(cmdlines, check_cancelled=_never_cancelled, maxjobs=None):
+def run(cmdlines, check_cancelled=_never_cancelled, maxjobs=None, newline_on_success=False):
   js = Jobset(check_cancelled,
-              maxjobs if maxjobs is not None else _DEFAULT_MAX_JOBS)
+              maxjobs if maxjobs is not None else _DEFAULT_MAX_JOBS,
+              newline_on_success)
   for cmdline in shuffle_iteratable(cmdlines):
     if not js.start(cmdline):
       break