|  | @@ -29,7 +29,6 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  """Run a group of subprocesses and then finish."""
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -import hashlib
 | 
	
		
			
				|  |  |  import multiprocessing
 | 
	
		
			
				|  |  |  import os
 | 
	
		
			
				|  |  |  import platform
 | 
	
	
		
			
				|  | @@ -149,7 +148,7 @@ def which(filename):
 | 
	
		
			
				|  |  |  class JobSpec(object):
 | 
	
		
			
				|  |  |    """Specifies what to run for a job."""
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  def __init__(self, cmdline, shortname=None, environ=None, hash_targets=None,
 | 
	
		
			
				|  |  | +  def __init__(self, cmdline, shortname=None, environ=None,
 | 
	
		
			
				|  |  |                 cwd=None, shell=False, timeout_seconds=5*60, flake_retries=0,
 | 
	
		
			
				|  |  |                 timeout_retries=0, kill_handler=None, cpu_cost=1.0,
 | 
	
		
			
				|  |  |                 verbose_success=False):
 | 
	
	
		
			
				|  | @@ -157,19 +156,14 @@ class JobSpec(object):
 | 
	
		
			
				|  |  |      Arguments:
 | 
	
		
			
				|  |  |        cmdline: a list of arguments to pass as the command line
 | 
	
		
			
				|  |  |        environ: a dictionary of environment variables to set in the child process
 | 
	
		
			
				|  |  | -      hash_targets: which files to include in the hash representing the jobs version
 | 
	
		
			
				|  |  | -                    (or empty, indicating the job should not be hashed)
 | 
	
		
			
				|  |  |        kill_handler: a handler that will be called whenever job.kill() is invoked
 | 
	
		
			
				|  |  |        cpu_cost: number of cores per second this job needs
 | 
	
		
			
				|  |  |      """
 | 
	
		
			
				|  |  |      if environ is None:
 | 
	
		
			
				|  |  |        environ = {}
 | 
	
		
			
				|  |  | -    if hash_targets is None:
 | 
	
		
			
				|  |  | -      hash_targets = []
 | 
	
		
			
				|  |  |      self.cmdline = cmdline
 | 
	
		
			
				|  |  |      self.environ = environ
 | 
	
		
			
				|  |  |      self.shortname = cmdline[0] if shortname is None else shortname
 | 
	
		
			
				|  |  | -    self.hash_targets = hash_targets or []
 | 
	
		
			
				|  |  |      self.cwd = cwd
 | 
	
		
			
				|  |  |      self.shell = shell
 | 
	
		
			
				|  |  |      self.timeout_seconds = timeout_seconds
 | 
	
	
		
			
				|  | @@ -180,7 +174,7 @@ class JobSpec(object):
 | 
	
		
			
				|  |  |      self.verbose_success = verbose_success
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    def identity(self):
 | 
	
		
			
				|  |  | -    return '%r %r %r' % (self.cmdline, self.environ, self.hash_targets)
 | 
	
		
			
				|  |  | +    return '%r %r' % (self.cmdline, self.environ)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    def __hash__(self):
 | 
	
		
			
				|  |  |      return hash(self.identity())
 | 
	
	
		
			
				|  | @@ -205,9 +199,8 @@ class JobResult(object):
 | 
	
		
			
				|  |  |  class Job(object):
 | 
	
		
			
				|  |  |    """Manages one job."""
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  def __init__(self, spec, bin_hash, newline_on_success, travis, add_env):
 | 
	
		
			
				|  |  | +  def __init__(self, spec, newline_on_success, travis, add_env):
 | 
	
		
			
				|  |  |      self._spec = spec
 | 
	
		
			
				|  |  | -    self._bin_hash = bin_hash
 | 
	
		
			
				|  |  |      self._newline_on_success = newline_on_success
 | 
	
		
			
				|  |  |      self._travis = travis
 | 
	
		
			
				|  |  |      self._add_env = add_env.copy()
 | 
	
	
		
			
				|  | @@ -249,7 +242,7 @@ class Job(object):
 | 
	
		
			
				|  |  |        self._process = try_start()
 | 
	
		
			
				|  |  |      self._state = _RUNNING
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  def state(self, update_cache):
 | 
	
		
			
				|  |  | +  def state(self):
 | 
	
		
			
				|  |  |      """Poll current state of the job. Prints messages at completion."""
 | 
	
		
			
				|  |  |      def stdout(self=self):
 | 
	
		
			
				|  |  |        self._tempfile.seek(0)
 | 
	
	
		
			
				|  | @@ -293,8 +286,6 @@ class Job(object):
 | 
	
		
			
				|  |  |              stdout() if self._spec.verbose_success else None,
 | 
	
		
			
				|  |  |              do_newline=self._newline_on_success or self._travis)
 | 
	
		
			
				|  |  |          self.result.state = 'PASSED'
 | 
	
		
			
				|  |  | -        if self._bin_hash:
 | 
	
		
			
				|  |  | -          update_cache.finished(self._spec.identity(), self._bin_hash)
 | 
	
		
			
				|  |  |      elif (self._state == _RUNNING and
 | 
	
		
			
				|  |  |            self._spec.timeout_seconds is not None and
 | 
	
		
			
				|  |  |            time.time() - self._start > self._spec.timeout_seconds):
 | 
	
	
		
			
				|  | @@ -329,7 +320,7 @@ class Jobset(object):
 | 
	
		
			
				|  |  |    """Manages one run of jobs."""
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    def __init__(self, check_cancelled, maxjobs, newline_on_success, travis,
 | 
	
		
			
				|  |  | -               stop_on_failure, add_env, cache):
 | 
	
		
			
				|  |  | +               stop_on_failure, add_env):
 | 
	
		
			
				|  |  |      self._running = set()
 | 
	
		
			
				|  |  |      self._check_cancelled = check_cancelled
 | 
	
		
			
				|  |  |      self._cancelled = False
 | 
	
	
		
			
				|  | @@ -338,9 +329,7 @@ class Jobset(object):
 | 
	
		
			
				|  |  |      self._maxjobs = maxjobs
 | 
	
		
			
				|  |  |      self._newline_on_success = newline_on_success
 | 
	
		
			
				|  |  |      self._travis = travis
 | 
	
		
			
				|  |  | -    self._cache = cache
 | 
	
		
			
				|  |  |      self._stop_on_failure = stop_on_failure
 | 
	
		
			
				|  |  | -    self._hashes = {}
 | 
	
		
			
				|  |  |      self._add_env = add_env
 | 
	
		
			
				|  |  |      self.resultset = {}
 | 
	
		
			
				|  |  |      self._remaining = None
 | 
	
	
		
			
				|  | @@ -367,37 +356,21 @@ class Jobset(object):
 | 
	
		
			
				|  |  |        if current_cpu_cost + spec.cpu_cost <= self._maxjobs: break
 | 
	
		
			
				|  |  |        self.reap()
 | 
	
		
			
				|  |  |      if self.cancelled(): return False
 | 
	
		
			
				|  |  | -    if spec.hash_targets:
 | 
	
		
			
				|  |  | -      if spec.identity() in self._hashes:
 | 
	
		
			
				|  |  | -        bin_hash = self._hashes[spec.identity()]
 | 
	
		
			
				|  |  | -      else:
 | 
	
		
			
				|  |  | -        bin_hash = hashlib.sha1()
 | 
	
		
			
				|  |  | -        for fn in spec.hash_targets:
 | 
	
		
			
				|  |  | -          with open(which(fn)) as f:
 | 
	
		
			
				|  |  | -            bin_hash.update(f.read())
 | 
	
		
			
				|  |  | -        bin_hash = bin_hash.hexdigest()
 | 
	
		
			
				|  |  | -        self._hashes[spec.identity()] = bin_hash
 | 
	
		
			
				|  |  | -      should_run = self._cache.should_run(spec.identity(), bin_hash)
 | 
	
		
			
				|  |  | -    else:
 | 
	
		
			
				|  |  | -      bin_hash = None
 | 
	
		
			
				|  |  | -      should_run = True
 | 
	
		
			
				|  |  | -    if should_run:
 | 
	
		
			
				|  |  | -      job = Job(spec,
 | 
	
		
			
				|  |  | -                bin_hash,
 | 
	
		
			
				|  |  | -                self._newline_on_success,
 | 
	
		
			
				|  |  | -                self._travis,
 | 
	
		
			
				|  |  | -                self._add_env)
 | 
	
		
			
				|  |  | -      self._running.add(job)
 | 
	
		
			
				|  |  | -      if not self.resultset.has_key(job.GetSpec().shortname):
 | 
	
		
			
				|  |  | -        self.resultset[job.GetSpec().shortname] = []
 | 
	
		
			
				|  |  | -    return True
 | 
	
		
			
				|  |  | +    job = Job(spec,
 | 
	
		
			
				|  |  | +              self._newline_on_success,
 | 
	
		
			
				|  |  | +              self._travis,
 | 
	
		
			
				|  |  | +              self._add_env)
 | 
	
		
			
				|  |  | +    self._running.add(job)
 | 
	
		
			
				|  |  | +    if not self.resultset.has_key(job.GetSpec().shortname):
 | 
	
		
			
				|  |  | +      self.resultset[job.GetSpec().shortname] = []
 | 
	
		
			
				|  |  | +      return True
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    def reap(self):
 | 
	
		
			
				|  |  |      """Collect the dead jobs."""
 | 
	
		
			
				|  |  |      while self._running:
 | 
	
		
			
				|  |  |        dead = set()
 | 
	
		
			
				|  |  |        for job in self._running:
 | 
	
		
			
				|  |  | -        st = job.state(self._cache)
 | 
	
		
			
				|  |  | +        st = job.state()
 | 
	
		
			
				|  |  |          if st == _RUNNING: continue
 | 
	
		
			
				|  |  |          if st == _FAILURE or st == _KILLED:
 | 
	
		
			
				|  |  |            self._failures += 1
 | 
	
	
		
			
				|  | @@ -450,15 +423,6 @@ def _never_cancelled():
 | 
	
		
			
				|  |  |    return False
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -# cache class that caches nothing
 | 
	
		
			
				|  |  | -class NoCache(object):
 | 
	
		
			
				|  |  | -  def should_run(self, cmdline, bin_hash):
 | 
	
		
			
				|  |  | -    return True
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  def finished(self, cmdline, bin_hash):
 | 
	
		
			
				|  |  | -    pass
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  def tag_remaining(xs):
 | 
	
		
			
				|  |  |    staging = []
 | 
	
		
			
				|  |  |    for x in xs:
 | 
	
	
		
			
				|  | @@ -477,12 +441,10 @@ def run(cmdlines,
 | 
	
		
			
				|  |  |          travis=False,
 | 
	
		
			
				|  |  |          infinite_runs=False,
 | 
	
		
			
				|  |  |          stop_on_failure=False,
 | 
	
		
			
				|  |  | -        cache=None,
 | 
	
		
			
				|  |  |          add_env={}):
 | 
	
		
			
				|  |  |    js = Jobset(check_cancelled,
 | 
	
		
			
				|  |  |                maxjobs if maxjobs is not None else _DEFAULT_MAX_JOBS,
 | 
	
		
			
				|  |  | -              newline_on_success, travis, stop_on_failure, add_env,
 | 
	
		
			
				|  |  | -              cache if cache is not None else NoCache())
 | 
	
		
			
				|  |  | +              newline_on_success, travis, stop_on_failure, add_env)
 | 
	
		
			
				|  |  |    for cmdline, remaining in tag_remaining(cmdlines):
 | 
	
		
			
				|  |  |      if not js.start(cmdline):
 | 
	
		
			
				|  |  |        break
 |