Module: ParallelCucumber::Helper::Processes

Defined in:
lib/parallel_cucumber/helper/processes.rb

Class Method Summary collapse

Class Method Details

.all_pids_dead?(root, logger, tree = nil, old_tree = nil) ⇒ Boolean

Returns:

  • (Boolean)


54
55
56
57
58
# 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) ⇒ Object



9
10
11
12
13
14
15
16
17
# 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| ... } ⇒ Object

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.

Yields:

  • (pid, old_tree_node)


63
64
65
66
67
68
69
70
71
72
73
74
# 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) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 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?Boolean

Returns:

  • (Boolean)


5
6
7
# File 'lib/parallel_cucumber/helper/processes.rb', line 5

def ms_windows?
  RUBY_PLATFORM =~ /mswin|mingw|migw32|cygwin/
end

.ps_treeObject



19
20
21
22
23
24
25
26
27
28
29
30
# 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