module IPAddress::ToSWithNetmaskForNetworks refine IPAddress::IPv6 do def to_s 128 == prefix ? super() : to_string end end refine IPAddress::IPv4 do def to_s 32 == prefix ? super() : to_string end end end class Measured class V attr_reader :value, :length def initialize( value, length = nil) @value, @length = value, length || value.length end def inspect() "#" end alias :to_s :value alias :to_str :value end class < v %w[KiB MiBy GiByt TiByte ExiByte PetiByte].each_with_index do |m| v /= 1024 return units '%.1f ' % v, m if 512 > v end units '%d ' % v, :PetiByte end def bytes2 v r = (v.to_i / 1024 / 1024).to_s return '·' if 0 == r r. reverse. each_char. each_slice( 3). to_a. reverse. map {|a| a.reverse.join }. join " " end alias bytes bytes2 def units val, unit v = "#{val}\e[1;30m#{unit}\e[0m" V.new v, v.length - 11 end def seconds i i = i.to_i return V.new "\e[1;30m·\e[0m", 1 if 0 == i return units '%d ' % i, :s if 90 > i i /= 60 return units '%d ' % i, :mi if 90 > i i /= 60 return units '%d ' % i, :hou if 36 > i i /= 24 return units '%d ' % i, :days if 14 > i j = i / 7 return units '%d ' % j, :weeks if 8 > j j = i / 30 return units '%d ' % j, :months if 11 > j i /= 365.0 return units '%.2f ' % i, :years if 550 > i units '%d ' % i, :years end end end class ColoredString attr_reader :string, :color_codes def initialize string, color_codes @string, @color_codes = string, color_codes end def inspect "#" end def length() @string.length end alias size length def to_s() "\e[#{@color_codes}m#{@string}\e[0m" end alias to_str to_s include Comparable def <=>(o) @string <=> o.string end end class TablizedOutput def initialize header, stdout: nil, format: nil @header = header.map &:to_s @columnc = header.size @format = format || ['>']*@columnc @maxs = header.map &:length @stdout ||= STDOUT @lines = [] end class B include Comparable def <=>(o) @v <=> o.v end end class V < B attr_reader :v, :s def initialize( v, s=nil) @v, @s = v, s || "#{v}" end def to_s() @s.to_s end def length() @s.length end def inspect() "#" end end class Percentage < B attr_reader :v, :w def initialize( v, w=nil) @v, @w = v, w || 10 end def length() @w end def inspect() "#" end def to_s vw = v*w percent = (100*v).round vwi = vw.to_i rounded = (vw+0.5).to_i s = "%*s" % [w, 0==percent ? '·' : percent] pre = "\e[1;4;#{0.75>v ? 32 : 31}m" mid = (vw % 1) > 0.5 ? "\e[2m" : "\e[0m" "#{pre}#{s[0...vwi]}#{mid}#{s[vwi]}\e[0m#{s[(vwi+1)..-1]}" end end def push fields fields = fields.map do |x| case x when String, ColoredString, B then x else V.new x end end @maxs = @columnc.times.map {|i| [@maxs[i], fields[i].length].max } @lines.push fields end def pushs lines lines.each &method( :push) end def print order: nil ls = @lines if order eval <<-EOC, binding, __FILE__, 1+__LINE__ ls = ls.sort {|a,b| [#{order.map {|i| 0 < i ? "a[#{i-1}]" : "b[#{-i-1}]" }.join ', '}] <=> [#{order.map {|i| 0 < i ? "b[#{i-1}]" : "a[#{-i-1}]" }.join ', '}] } EOC end @stdout.puts \ @header.each_with_index.map {|s, i| "#{' ' * (@maxs[i] - s.length)}#{s}" }.join( ' | ') ls.each_with_index do |l, i| @stdout.puts \ l.each_with_index.map {|s, i| pad = ' ' * (@maxs[i] - s.length) case @format[i] when '<' "#{s}#{pad}" else "#{pad}#{s}" end }.join( "\e[3#{i.even? ? 6 : 3}m | \e[0m") end end def virt v ha = v.respond_to?( :ha) ? v.ha : nil unknown = V.new 0, '-' push [ case v.status when "running", "online" then ColoredString.new v.status, "32" when "stopped" then ColoredString.new v.status, "31" else v.status end, ha&.state || '·', case v.t when "nd" then ColoredString.new v.sid, "33" when "qm" then ColoredString.new v.sid, "35" when "ct" then ColoredString.new v.sid, "36" else v.sid end, v.name, v.node.is_a?(String) ? v.node : v.node.node, v.respond_to?(:uptime) ? V.new( v.uptime, Measured.seconds( v.uptime)) : unknown, v.respond_to?(:cpu) ? Percentage.new( v.cpu) : unknown, v.respond_to?(:mem) ? V.new( v.mem, Measured.bytes( v.mem)) : unknown, v.respond_to?(:maxmem) ? Percentage.new( v.mem/v.maxmem.to_f) : unknown, v.respond_to?(:disk) ? V.new( v.disk.to_i, Measured.bytes( v.disk.to_i)) : unknown, if v.respond_to?(:maxdisk) and 0 < v.maxdisk.to_i Percentage.new( v.disk.to_f/v.maxdisk.to_f) else unknown end, ] end end