lib/pstree.rb
require 'pstree/version' class PSTree class ProcStruct def initialize(ppid, pid, user, cmd) @ppid, @pid, @user, @cmd = ppid.to_i, pid.to_i, user, cmd end attr_reader :ppid, :pid, :user, :cmd def to_s "%05u %s (%s)" % [ pid, cmd, user ] end end include Enumerable def initialize(root_pid = nil, charset: 'UTF-8') @charset = charset.to_s.upcase @root_pid = root_pid.to_i end def children_zero(last) if @charset == 'UTF-8' last ? '└─ ' : ' ' else last ? '`- ' : ' ' end end def children_not_zero(last) if @charset == 'UTF-8' last ? '├─ ' : '│ ' else last ? '+- ' : '| ' end end def to_s build result = '' recurse @root_pid, -> children, last { if children.zero? result << children_zero(last) else result << children_not_zero(last) end } do |ps| result << ps.to_s << "\n" end result end def each(&block) build recurse @root_pid, &block self end private def build @child_count = [ 0 ] @process = {} @pstree = Hash.new { |h,k| h[k] = [] } psoutput = `/bin/ps axww -o ppid,pid,user,command` psoutput.each_line do |line| next if line !~ /^\s*\d+/ line.strip! ps = ProcStruct.new(*line.split(/\s+/, 4)) @process[ps.pid] = ps @pstree[ps.ppid] << ps end end def recurse(pid, shift_callback = nil, level = 0, in_root = false, &node_callback) in_root = in_root || @root_pid == 0 || @root_pid == pid @child_count[level] = @pstree[pid].size for l in 0...level shift_callback and shift_callback.call(@child_count[l], l == level - 1) end node_callback and process = @process[pid] and node_callback.call(process) if @pstree.key?(pid) @child_count[level] = @pstree[pid].size - 1 @pstree[pid].each do |ps| recurse(ps.pid, shift_callback, level + 1, in_root, &node_callback) @child_count[level] -= 1 end end @pstree.delete pid end end