module ParallelCucumber::Helper::Processes

Public Class Methods

all_pids_dead?(root, logger, tree = nil, old_tree = nil) click to toggle source
# File lib/parallel_cucumber/helper/processes.rb, line 54
def all_pids_dead?(root, logger, tree = nil, old_tree = nil)
  # Note: returns from THIS function as well as descendants: short-circuit evaluation if any descendants remain.
  descendants(root, logger, tree, old_tree, 'dead?') { return false }
  true
end
cp_rv(source, dest, logger = nil) click to toggle source
# File lib/parallel_cucumber/helper/processes.rb, line 9
def cp_rv(source, dest, logger = nil)
  cp_out = if ms_windows?
             %x(powershell cp #{source} #{dest} -recurse -force 2>&1)
           else
             # Use system cp -r because Ruby's has crap diagnostics in weird situations.
             %x(cp -Rv #{source} #{dest} 2>&1)
           end
  logger.debug("Copy of #{source} to #{dest} said: #{cp_out}") if logger
end
descendants(pid, logger, tree = nil, old_tree = nil, why = '-', level = 0) { |pid, old_tree_node| ... } click to toggle source

Walks old_tree, and yields all processes (alive or dead) that match the pid, start time, and command in the new tree. Note that this will fumble children created since old_tree was created, but this thing is riddled with race conditions anyway.

# File lib/parallel_cucumber/helper/processes.rb, line 63
def descendants(pid, logger, tree = nil, old_tree = nil, why = '-', # rubocop:disable Metrics/ParameterLists
                level = 0, &block)
  tree ||= ps_tree
  old_tree ||= tree
  old_tree_node = old_tree[pid]
  unless old_tree_node
    logger.warn "== old tree node went missing - #{why} - skipping subtree level=#{level}: #{pid}"
    return
  end
  old_tree_node.fetch(:children, []).each { |c| descendants(c, logger, tree, old_tree, why, level + 1, &block) }
  yield(pid, old_tree_node) if tree[pid] && (tree[pid][:signature] == old_tree_node[:signature])
end
kill_tree(sig, root, logger, tree = nil, old_tree = nil) click to toggle source
# File lib/parallel_cucumber/helper/processes.rb, line 32
def kill_tree(sig, root, logger, tree = nil, old_tree = nil)
  if ms_windows?
    system("taskkill /pid #{root} /T")
  else
    descendants(root, logger, tree, old_tree, 'kill') do |pid, node|
      begin
        logger.warn "Sending signal #{sig} to #{node}"
        Process.kill(sig, pid.to_i)
      rescue Errno::ESRCH
        nil # It's gone already? Hurrah!
      end
    end
  end
  # Let's kill pid unconditionally: descendants will go astray once reparented.
  begin
    logger.warn "Sending signal #{sig} to root process #{root} just in case"
    Process.kill(sig, root.to_i)
  rescue Errno::ESRCH
    nil # It's gone already? Hurrah!
  end
end
ms_windows?() click to toggle source
# File lib/parallel_cucumber/helper/processes.rb, line 5
def ms_windows?
  RUBY_PLATFORM =~ /mswin|mingw|migw32|cygwin/
end
ps_tree() click to toggle source
# File lib/parallel_cucumber/helper/processes.rb, line 19
def ps_tree
  if ms_windows?
    system('powershell scripts/process_tree.ps1')
  else
    %x(ps -ax -o ppid= -o pid= -o lstart= -o command=)
      .each_line.map { |l| l.strip.split(/ +/, 3) }.to_a
      .each_with_object({}) do |(ppid, pid, signature), tree|
        (tree[pid] ||= { children: [] })[:signature] = signature
        (tree[ppid] ||= { children: [] })[:children] << pid
      end
  end
end