hackmac 1.2.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/bin/gfxmon +31 -77
- data/hackmac.gemspec +5 -5
- data/lib/hackmac/graph/display.rb +200 -0
- data/lib/hackmac/graph.rb +201 -0
- data/lib/hackmac/version.rb +1 -1
- data/lib/hackmac.rb +1 -0
- metadata +6 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 7b280a3a7695d3ca2acc44f274d9602bcfccb8f24ea43a6e49b490830efed1e0
         | 
| 4 | 
            +
              data.tar.gz: a8fdf6d9ccaf9cf736218a10e462c4522139e938ef0677234fe48af3ea278179
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 6cb72a600ddd93ac37f453b952b49e748a40626f1405d89803a64401c8aee7331c800d5b07d699ec45132ce1a26aa0288f2969798a1dcb6b1ee7598e1a090584
         | 
| 7 | 
            +
              data.tar.gz: 32d42271e8814c01c80ac2ecb63d15080042abc9a2f265fccd82536680dbcfd17e595ba2cee78c05ee73a6595c41e0212a6ed834ca9c52929cb3ab40f595c633
         | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            1. | 
| 1 | 
            +
            1.4.0
         | 
    
        data/bin/gfxmon
    CHANGED
    
    | @@ -13,7 +13,7 @@ require 'amatch' | |
| 13 13 | 
             
            require 'search_ui'
         | 
| 14 14 | 
             
            include SearchUI
         | 
| 15 15 |  | 
| 16 | 
            -
            $opts = go 'c: | 
| 16 | 
            +
            $opts = go 'c:m:n:jlh', defaults: { ?s => true, ?n => 5 }
         | 
| 17 17 |  | 
| 18 18 | 
             
            def usage
         | 
| 19 19 | 
             
              puts <<~end
         | 
| @@ -25,7 +25,7 @@ def usage | |
| 25 25 | 
             
                  -l          output GPU performance data as list
         | 
| 26 26 | 
             
                  -j          output GPU performance data as json
         | 
| 27 27 | 
             
                  -n SECONDS  measure every SECONDS
         | 
| 28 | 
            -
                  - | 
| 28 | 
            +
                  -m METRIC   output graph for performance METRIC
         | 
| 29 29 | 
             
                  -c COLOR    output graph in this terminal COLOR (between 0 - 255)
         | 
| 30 30 |  | 
| 31 31 | 
             
              end
         | 
| @@ -45,23 +45,16 @@ def ps | |
| 45 45 | 
             
              }
         | 
| 46 46 | 
             
            end
         | 
| 47 47 |  | 
| 48 | 
            -
            def format_bytes(n, v)
         | 
| 49 | 
            -
              if n =~ /bytes/i
         | 
| 50 | 
            -
                Tins::Unit.format(v, format: '%.3f%U', unit: '')
         | 
| 51 | 
            -
              else
         | 
| 52 | 
            -
                v.to_s
         | 
| 53 | 
            -
              end
         | 
| 54 | 
            -
            end
         | 
| 55 | 
            -
             | 
| 56 48 | 
             
            def list(ps)
         | 
| 57 49 | 
             
              max = ps.keys.max_by(&:size)&.size&.to_i
         | 
| 50 | 
            +
              include Hackmac::Graph::Formatters
         | 
| 58 51 | 
             
              puts ps.map { |n, v|
         | 
| 59 | 
            -
                ("%-#{max}s" % n) + " " + ("%s" %  | 
| 52 | 
            +
                ("%-#{max}s" % n) + " " + ("%s" % send(derive_formatter(n), v)).bold
         | 
| 60 53 | 
             
              }
         | 
| 61 54 | 
             
            end
         | 
| 62 55 |  | 
| 63 56 | 
             
            def choose_metric(ps)
         | 
| 64 | 
            -
              case metric = $opts[? | 
| 57 | 
            +
              case metric = $opts[?m]
         | 
| 65 58 | 
             
              when nil
         | 
| 66 59 | 
             
                ps_names = ps.keys
         | 
| 67 60 | 
             
                metric = Search.new(
         | 
| @@ -87,75 +80,36 @@ def choose_metric(ps) | |
| 87 80 | 
             
              fail "Metric #{metric} not known"
         | 
| 88 81 | 
             
            end
         | 
| 89 82 |  | 
| 83 | 
            +
            def derive_formatter(metric)
         | 
| 84 | 
            +
              case metric
         | 
| 85 | 
            +
              when /bytes/i
         | 
| 86 | 
            +
                :as_bytes
         | 
| 87 | 
            +
              when /Hz/
         | 
| 88 | 
            +
                :as_hertz
         | 
| 89 | 
            +
              when /\(C\)/
         | 
| 90 | 
            +
                :as_celsius
         | 
| 91 | 
            +
              when /\(%\)/
         | 
| 92 | 
            +
                :as_percent
         | 
| 93 | 
            +
              else
         | 
| 94 | 
            +
                :as_default
         | 
| 95 | 
            +
              end
         | 
| 96 | 
            +
            end
         | 
| 97 | 
            +
             | 
| 90 98 | 
             
            def display_graph
         | 
| 91 99 | 
             
              if metric = choose_metric(ps)
         | 
| 92 100 | 
             
                sleep_duration = [ 1, ($opts[?n] || 10).to_i ].max
         | 
| 93 | 
            -
                 | 
| 94 | 
            -
                 | 
| 95 | 
            -
             | 
| 96 | 
            -
                   | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
                   | 
| 100 | 
            -
             | 
| 101 | 
            -
             | 
| 102 | 
            -
                }
         | 
| 103 | 
            -
                loop do
         | 
| 104 | 
            -
                  print clear_screen
         | 
| 105 | 
            -
             | 
| 106 | 
            -
                  lines, cols = Tins::Terminal.winsize
         | 
| 107 | 
            -
             | 
| 108 | 
            -
                  as_title = -> t {
         | 
| 109 | 
            -
                    move_to(lines, (cols - t.size) / 2) { t.bold }
         | 
| 110 | 
            -
                  }
         | 
| 111 | 
            -
             | 
| 112 | 
            -
                  case value = ps[metric]
         | 
| 113 | 
            -
                  when Float
         | 
| 114 | 
            -
                    data << value
         | 
| 115 | 
            -
                  else
         | 
| 116 | 
            -
                    data << value.to_i
         | 
| 117 | 
            -
                  end
         | 
| 118 | 
            -
                  data = data.last(cols)
         | 
| 119 | 
            -
             | 
| 120 | 
            -
                  y_width = (data.max - data.min).to_f
         | 
| 121 | 
            -
                  if y_width == 0
         | 
| 122 | 
            -
                    print(
         | 
| 123 | 
            -
                      as_title.("#{metric} / #{sleep_duration}s"),
         | 
| 124 | 
            -
                      move_to(lines / 2, (cols - "no data".size) / 2) { "no data".italic }
         | 
| 125 | 
            -
                    )
         | 
| 126 | 
            -
                    sleep sleep_duration
         | 
| 127 | 
            -
                    print clear_screen
         | 
| 128 | 
            -
                    next
         | 
| 129 | 
            -
                  end
         | 
| 130 | 
            -
             | 
| 131 | 
            -
                  unless c = $opts[?c]
         | 
| 132 | 
            -
                    cs = (21..226).select { |d|
         | 
| 133 | 
            -
                      Term::ANSIColor::Attribute[d].to_rgb_triple.to_hsl_triple.
         | 
| 134 | 
            -
                        lightness < 40
         | 
| 135 | 
            -
                    }
         | 
| 136 | 
            -
                    c = cs[ metric.bytes.reduce(0, :+) % cs.size ]
         | 
| 137 | 
            -
                  end
         | 
| 138 | 
            -
                  color       = Term::ANSIColor::Attribute[c]
         | 
| 139 | 
            -
                  color_light = color.to_rgb_triple.to_hsl_triple.lighten(15) rescue color
         | 
| 140 | 
            -
             | 
| 141 | 
            -
                  data.each_with_index do |value, x|
         | 
| 142 | 
            -
                    x = x + cols - data.size + 1
         | 
| 143 | 
            -
                    y = lines - (((value - data.min) * lines / y_width)).round + 1
         | 
| 144 | 
            -
                    y.upto(lines) do |iy|
         | 
| 145 | 
            -
                      print move_to(iy, x) { ' '.on_color(y == iy ? color : color_light) }
         | 
| 146 | 
            -
                    end
         | 
| 147 | 
            -
                  end
         | 
| 148 | 
            -
             | 
| 149 | 
            -
                  print(
         | 
| 150 | 
            -
                    as_title.("#{metric} #{format_bytes(metric, data.last)} / #{sleep_duration}s"),
         | 
| 151 | 
            -
                    move_home { format_bytes(metric, data.max).bold },
         | 
| 152 | 
            -
                    move_to_line(lines) { format_bytes(metric, data.min).bold }
         | 
| 153 | 
            -
                  )
         | 
| 154 | 
            -
             | 
| 155 | 
            -
                  sleep sleep_duration
         | 
| 156 | 
            -
                end
         | 
| 101 | 
            +
                format_value = derive_formatter(metric)
         | 
| 102 | 
            +
                graph = Hackmac::Graph.new(
         | 
| 103 | 
            +
                  title: metric,
         | 
| 104 | 
            +
                  sleep: sleep_duration,
         | 
| 105 | 
            +
                  value: -> _ { ps[metric] },
         | 
| 106 | 
            +
                  color: $opts[?c],
         | 
| 107 | 
            +
                  format_value:
         | 
| 108 | 
            +
                )
         | 
| 109 | 
            +
                graph.start
         | 
| 157 110 | 
             
              end
         | 
| 158 | 
            -
             | 
| 111 | 
            +
            ensure 
         | 
| 112 | 
            +
              graph&.stop
         | 
| 159 113 | 
             
            end
         | 
| 160 114 |  | 
| 161 115 | 
             
            case
         | 
    
        data/hackmac.gemspec
    CHANGED
    
    | @@ -1,19 +1,19 @@ | |
| 1 1 | 
             
            # -*- encoding: utf-8 -*-
         | 
| 2 | 
            -
            # stub: hackmac 1. | 
| 2 | 
            +
            # stub: hackmac 1.4.0 ruby lib
         | 
| 3 3 |  | 
| 4 4 | 
             
            Gem::Specification.new do |s|
         | 
| 5 5 | 
             
              s.name = "hackmac".freeze
         | 
| 6 | 
            -
              s.version = "1. | 
| 6 | 
            +
              s.version = "1.4.0"
         | 
| 7 7 |  | 
| 8 8 | 
             
              s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
         | 
| 9 9 | 
             
              s.require_paths = ["lib".freeze]
         | 
| 10 10 | 
             
              s.authors = ["Florian Frank".freeze]
         | 
| 11 | 
            -
              s.date = "2023-05- | 
| 11 | 
            +
              s.date = "2023-05-28"
         | 
| 12 12 | 
             
              s.description = "This ruby gem provides some useful tools for working with a Hackintosh.".freeze
         | 
| 13 13 | 
             
              s.email = "flori@ping.de".freeze
         | 
| 14 14 | 
             
              s.executables = ["efi".freeze, "gfxmon".freeze, "usb".freeze]
         | 
| 15 | 
            -
              s.extra_rdoc_files = ["README.md".freeze, "lib/hackmac.rb".freeze, "lib/hackmac/asset_tools.rb".freeze, "lib/hackmac/config.rb".freeze, "lib/hackmac/disks.rb".freeze, "lib/hackmac/github_source.rb".freeze, "lib/hackmac/kext.rb".freeze, "lib/hackmac/kext_upgrader.rb".freeze, "lib/hackmac/oc.rb".freeze, "lib/hackmac/oc_upgrader.rb".freeze, "lib/hackmac/oc_validator.rb".freeze, "lib/hackmac/plist.rb".freeze, "lib/hackmac/url_download.rb".freeze, "lib/hackmac/utils.rb".freeze, "lib/hackmac/version.rb".freeze]
         | 
| 16 | 
            -
              s.files = [".gitignore".freeze, "Gemfile".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "bin/efi".freeze, "bin/gfxmon".freeze, "bin/usb".freeze, "hackmac.gemspec".freeze, "lib/hackmac.rb".freeze, "lib/hackmac/asset_tools.rb".freeze, "lib/hackmac/config.rb".freeze, "lib/hackmac/disks.rb".freeze, "lib/hackmac/github_source.rb".freeze, "lib/hackmac/hackmac.yml".freeze, "lib/hackmac/kext.rb".freeze, "lib/hackmac/kext_upgrader.rb".freeze, "lib/hackmac/oc.rb".freeze, "lib/hackmac/oc_upgrader.rb".freeze, "lib/hackmac/oc_validator.rb".freeze, "lib/hackmac/plist.rb".freeze, "lib/hackmac/url_download.rb".freeze, "lib/hackmac/utils.rb".freeze, "lib/hackmac/version.rb".freeze]
         | 
| 15 | 
            +
              s.extra_rdoc_files = ["README.md".freeze, "lib/hackmac.rb".freeze, "lib/hackmac/asset_tools.rb".freeze, "lib/hackmac/config.rb".freeze, "lib/hackmac/disks.rb".freeze, "lib/hackmac/github_source.rb".freeze, "lib/hackmac/graph.rb".freeze, "lib/hackmac/graph/display.rb".freeze, "lib/hackmac/kext.rb".freeze, "lib/hackmac/kext_upgrader.rb".freeze, "lib/hackmac/oc.rb".freeze, "lib/hackmac/oc_upgrader.rb".freeze, "lib/hackmac/oc_validator.rb".freeze, "lib/hackmac/plist.rb".freeze, "lib/hackmac/url_download.rb".freeze, "lib/hackmac/utils.rb".freeze, "lib/hackmac/version.rb".freeze]
         | 
| 16 | 
            +
              s.files = [".gitignore".freeze, "Gemfile".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "bin/efi".freeze, "bin/gfxmon".freeze, "bin/usb".freeze, "hackmac.gemspec".freeze, "lib/hackmac.rb".freeze, "lib/hackmac/asset_tools.rb".freeze, "lib/hackmac/config.rb".freeze, "lib/hackmac/disks.rb".freeze, "lib/hackmac/github_source.rb".freeze, "lib/hackmac/graph.rb".freeze, "lib/hackmac/graph/display.rb".freeze, "lib/hackmac/hackmac.yml".freeze, "lib/hackmac/kext.rb".freeze, "lib/hackmac/kext_upgrader.rb".freeze, "lib/hackmac/oc.rb".freeze, "lib/hackmac/oc_upgrader.rb".freeze, "lib/hackmac/oc_validator.rb".freeze, "lib/hackmac/plist.rb".freeze, "lib/hackmac/url_download.rb".freeze, "lib/hackmac/utils.rb".freeze, "lib/hackmac/version.rb".freeze]
         | 
| 17 17 | 
             
              s.homepage = "http://github.com/flori/hackmac".freeze
         | 
| 18 18 | 
             
              s.rdoc_options = ["--title".freeze, "Hackmac - Some useful tools for working with a Hackintosh".freeze, "--main".freeze, "README.md".freeze]
         | 
| 19 19 | 
             
              s.rubygems_version = "3.3.26".freeze
         | 
| @@ -0,0 +1,200 @@ | |
| 1 | 
            +
            class Hackmac::Graph
         | 
| 2 | 
            +
              class Display
         | 
| 3 | 
            +
                ANSI = Term::ANSIColor
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                class Cell < Struct.new(:char, :color, :on_color, :styles)
         | 
| 6 | 
            +
                  def ==(other)
         | 
| 7 | 
            +
                    to_a == other.to_a
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def to_s
         | 
| 11 | 
            +
                    ANSI.color(color) {
         | 
| 12 | 
            +
                      ANSI.on_color(on_color) {
         | 
| 13 | 
            +
                        styles.inject(char) { |c, s|
         | 
| 14 | 
            +
                          ANSI.send(s) { c }
         | 
| 15 | 
            +
                        }
         | 
| 16 | 
            +
                      }
         | 
| 17 | 
            +
                    }
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def initialize(lines, columns)
         | 
| 22 | 
            +
                  @lines_range   = 1..lines
         | 
| 23 | 
            +
                  @columns_range = 1..columns
         | 
| 24 | 
            +
                  clear
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def clear
         | 
| 28 | 
            +
                  @x        = 1
         | 
| 29 | 
            +
                  @y        = 1
         | 
| 30 | 
            +
                  @color    = 15
         | 
| 31 | 
            +
                  @on_color = 0
         | 
| 32 | 
            +
                  @styles   = []
         | 
| 33 | 
            +
                  @cells    =
         | 
| 34 | 
            +
                    Array.new(lines) {
         | 
| 35 | 
            +
                      Array.new(columns) {
         | 
| 36 | 
            +
                        Cell.new(' ', @color, @on_color, @styles)
         | 
| 37 | 
            +
                      }
         | 
| 38 | 
            +
                    }
         | 
| 39 | 
            +
                  reset
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                def reset
         | 
| 43 | 
            +
                  @color    = 15
         | 
| 44 | 
            +
                  @on_color = 0
         | 
| 45 | 
            +
                  @styles   = []
         | 
| 46 | 
            +
                  self
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                def each(&block)
         | 
| 50 | 
            +
                  Enumerator.new do |enum|
         | 
| 51 | 
            +
                    @lines_range.each do |y|
         | 
| 52 | 
            +
                      @columns_range.each do |x|
         | 
| 53 | 
            +
                        enum.yield y, x, @cells[y - 1][x - 1]
         | 
| 54 | 
            +
                      end
         | 
| 55 | 
            +
                    end
         | 
| 56 | 
            +
                  end.each(&block)
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                def -(old)
         | 
| 60 | 
            +
                  dimensions != old.dimensions and raise ArgumentError,
         | 
| 61 | 
            +
                    "old dimensions #{old.dimensions.inspect} don't match #{dimensions.inspect}"
         | 
| 62 | 
            +
                  result = ''
         | 
| 63 | 
            +
                  each.zip(old.each) do |(my, mx, me), (_, _, old)|
         | 
| 64 | 
            +
                    if me != old
         | 
| 65 | 
            +
                      result << ANSI.move_to(my, mx) << me.to_s
         | 
| 66 | 
            +
                    end
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
                  result
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                def to_s
         | 
| 72 | 
            +
                  each.inject(ANSI.clear_screen)  do |s, (y, x, c)|
         | 
| 73 | 
            +
                    s << ANSI.move_to(y, x) << c.to_s
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                def inspect
         | 
| 78 | 
            +
                  "#<#{self.class}: #{columns}×#{lines}>"
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                attr_reader :x
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                attr_reader :y
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                def lines
         | 
| 86 | 
            +
                  @lines_range.end
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                def columns
         | 
| 90 | 
            +
                  @columns_range.end
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                def dimensions
         | 
| 94 | 
            +
                  [ lines, columns ]
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                def styled(*s)
         | 
| 98 | 
            +
                  if nope = s.find { !style?(_1) }
         | 
| 99 | 
            +
                    raise ArgumentError, "#{nope} is not a style"
         | 
| 100 | 
            +
                  end
         | 
| 101 | 
            +
                  @styles = s
         | 
| 102 | 
            +
                  self
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                def at(y, x)
         | 
| 106 | 
            +
                  @lines_range.include?(y) or
         | 
| 107 | 
            +
                    raise ArgumentError, "y #{y} out of lines range #@lines_range"
         | 
| 108 | 
            +
                  @columns_range.include?(x) or
         | 
| 109 | 
            +
                    raise ArgumentError, "x #{x} out of columns range #@columns_range"
         | 
| 110 | 
            +
                  @y, @x = y, x
         | 
| 111 | 
            +
                  self
         | 
| 112 | 
            +
                end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                def put(char)
         | 
| 115 | 
            +
                  char.size == 1 or
         | 
| 116 | 
            +
                    raise ArgumentError, "#{char} is not single character"
         | 
| 117 | 
            +
                  @cells[@y - 1][@x - 1] = Cell.new(char, @color, @on_color, @styles)
         | 
| 118 | 
            +
                  self
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                def write(string)
         | 
| 122 | 
            +
                  string.each_char do |char|
         | 
| 123 | 
            +
                    put(char)
         | 
| 124 | 
            +
                    if x < columns - 1
         | 
| 125 | 
            +
                      at(y, x + 1)
         | 
| 126 | 
            +
                    else
         | 
| 127 | 
            +
                      break
         | 
| 128 | 
            +
                    end
         | 
| 129 | 
            +
                  end
         | 
| 130 | 
            +
                  self
         | 
| 131 | 
            +
                end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                def top
         | 
| 134 | 
            +
                  at(1, x)
         | 
| 135 | 
            +
                end
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                def bottom
         | 
| 138 | 
            +
                  at(lines, x)
         | 
| 139 | 
            +
                end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                def left
         | 
| 142 | 
            +
                  at(y, 1)
         | 
| 143 | 
            +
                end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                def right
         | 
| 146 | 
            +
                  at(y, columns)
         | 
| 147 | 
            +
                end
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                def centered
         | 
| 150 | 
            +
                  at(lines / 2, columns / 2)
         | 
| 151 | 
            +
                end
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                def write_centered(string)
         | 
| 154 | 
            +
                  at(@y, (columns - string.size) / 2).write(string)
         | 
| 155 | 
            +
                end
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                def get
         | 
| 158 | 
            +
                  @cells[@y - 1][@x - 1]
         | 
| 159 | 
            +
                end
         | 
| 160 | 
            +
             | 
| 161 | 
            +
                def color(color)
         | 
| 162 | 
            +
                  @color = attribute!(color)
         | 
| 163 | 
            +
                  self
         | 
| 164 | 
            +
                end
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                def on_color(on_color)
         | 
| 167 | 
            +
                  @on_color = attribute!(on_color)
         | 
| 168 | 
            +
                  self
         | 
| 169 | 
            +
                end
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                private
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                def style?(s)
         | 
| 174 | 
            +
                  [
         | 
| 175 | 
            +
                    :bold,
         | 
| 176 | 
            +
                    :dark,
         | 
| 177 | 
            +
                    :faint,
         | 
| 178 | 
            +
                    :italic,
         | 
| 179 | 
            +
                    :underline,
         | 
| 180 | 
            +
                    :underscore,
         | 
| 181 | 
            +
                    :blink,
         | 
| 182 | 
            +
                    :rapid_blink,
         | 
| 183 | 
            +
                    :reverse,
         | 
| 184 | 
            +
                    :negative,
         | 
| 185 | 
            +
                    :concealed,
         | 
| 186 | 
            +
                    :conceal,
         | 
| 187 | 
            +
                    :strikethrough,
         | 
| 188 | 
            +
                  ].member?(s)
         | 
| 189 | 
            +
                end
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                def attribute?(a)
         | 
| 192 | 
            +
                  Term::ANSIColor::Attribute[a]
         | 
| 193 | 
            +
                end
         | 
| 194 | 
            +
             | 
| 195 | 
            +
                def attribute!(a)
         | 
| 196 | 
            +
                  attribute?(a) or
         | 
| 197 | 
            +
                    raise ArgumentError, "#{a.inspect} is not a color attribute"
         | 
| 198 | 
            +
                end
         | 
| 199 | 
            +
              end
         | 
| 200 | 
            +
            end
         | 
| @@ -0,0 +1,201 @@ | |
| 1 | 
            +
            require 'term/ansicolor'
         | 
| 2 | 
            +
            require 'tins'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class Hackmac::Graph
         | 
| 5 | 
            +
              include Term::ANSIColor
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              include\
         | 
| 8 | 
            +
              module Formatters
         | 
| 9 | 
            +
                def as_bytes(value)
         | 
| 10 | 
            +
                  Tins::Unit.format(value, prefix: :uc, format: '%.3f%U', unit: 'B')
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def as_hertz(value)
         | 
| 14 | 
            +
                  Tins::Unit.format(value, prefix: :uc, format: '%.3f%U', unit: 'Hz')
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def as_celsius(value)
         | 
| 18 | 
            +
                  "#{value}°"
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def as_percent(value)
         | 
| 22 | 
            +
                  "#{value}%"
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def as_default(value)
         | 
| 26 | 
            +
                  value.to_s
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                self
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              def initialize(
         | 
| 33 | 
            +
                title:,
         | 
| 34 | 
            +
                value: -> i { 0 },
         | 
| 35 | 
            +
                format_value: nil,
         | 
| 36 | 
            +
                sleep: nil,
         | 
| 37 | 
            +
                color: nil
         | 
| 38 | 
            +
              )
         | 
| 39 | 
            +
                sleep >= 0 or raise ArgumentError, 'sleep has to be >= 0'
         | 
| 40 | 
            +
                @title        = title
         | 
| 41 | 
            +
                @value        = value
         | 
| 42 | 
            +
                @format_value = format_value
         | 
| 43 | 
            +
                @sleep        = sleep
         | 
| 44 | 
            +
                @continue     = false
         | 
| 45 | 
            +
                @data         = []
         | 
| 46 | 
            +
                @color        = color
         | 
| 47 | 
            +
                @mutex        = Mutex.new
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
              def start
         | 
| 51 | 
            +
                install_handlers
         | 
| 52 | 
            +
                full_reset
         | 
| 53 | 
            +
                start_loop
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              def stop
         | 
| 57 | 
            +
                full_reset
         | 
| 58 | 
            +
                @continue = false
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              private
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              def start_loop
         | 
| 64 | 
            +
                full_reset
         | 
| 65 | 
            +
                color       = pick_color
         | 
| 66 | 
            +
                color_light = color.to_rgb_triple.to_hsl_triple.lighten(15) rescue color
         | 
| 67 | 
            +
                i           = 0
         | 
| 68 | 
            +
                @continue = true
         | 
| 69 | 
            +
                while @continue
         | 
| 70 | 
            +
                  @full_reset and full_reset
         | 
| 71 | 
            +
                  perform hide_cursor
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  @data << @value.(i)
         | 
| 74 | 
            +
                  @data = data.last(columns)
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  y_width = (data.max - data.min).to_f
         | 
| 77 | 
            +
                  if y_width == 0
         | 
| 78 | 
            +
                    @display.reset.bottom.styled(:bold).
         | 
| 79 | 
            +
                      write_centered("#@title / #{sleep_duration}").
         | 
| 80 | 
            +
                      reset.centered.styled(:italic).write_centered("no data")
         | 
| 81 | 
            +
                    perform_display_diff
         | 
| 82 | 
            +
                    sleep_now
         | 
| 83 | 
            +
                    next
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                  @display.reset
         | 
| 87 | 
            +
                  data.each_with_index do |value, x|
         | 
| 88 | 
            +
                    x = x + columns - data.size + 1
         | 
| 89 | 
            +
                    y = lines - (((value - data.min) * lines / y_width)).round + 1
         | 
| 90 | 
            +
                    y.upto(lines) do |iy|
         | 
| 91 | 
            +
                      @display.at(iy, x).on_color(
         | 
| 92 | 
            +
                        y == iy ? color : color_light
         | 
| 93 | 
            +
                      ).write(' ')
         | 
| 94 | 
            +
                    end
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                  @display.reset.bottom.styled(:bold).
         | 
| 98 | 
            +
                    write_centered("#@title #{format_value(data.last)} / #{sleep_duration}")
         | 
| 99 | 
            +
                  @display.reset.styled(:bold).
         | 
| 100 | 
            +
                    left.top.write(format_value(data.max)).
         | 
| 101 | 
            +
                    left.bottom.write(format_value(data.min))
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                  perform_display_diff
         | 
| 104 | 
            +
                  sleep_now
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
              ensure
         | 
| 107 | 
            +
                stop
         | 
| 108 | 
            +
              end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
              def perform(*a)
         | 
| 111 | 
            +
                print *a
         | 
| 112 | 
            +
              end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
              def columns
         | 
| 115 | 
            +
                @display.columns
         | 
| 116 | 
            +
              end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
              def lines
         | 
| 119 | 
            +
                @display.lines
         | 
| 120 | 
            +
              end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
              attr_reader :data
         | 
| 123 | 
            +
             | 
| 124 | 
            +
              def sleep_duration
         | 
| 125 | 
            +
                "#{@sleep}s"
         | 
| 126 | 
            +
              end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
              def format_value(value)
         | 
| 129 | 
            +
                case @format_value
         | 
| 130 | 
            +
                when Proc
         | 
| 131 | 
            +
                  @format_value.(value)
         | 
| 132 | 
            +
                when Symbol
         | 
| 133 | 
            +
                  send(@format_value, value)
         | 
| 134 | 
            +
                else
         | 
| 135 | 
            +
                  send(:as_default, value)
         | 
| 136 | 
            +
                end
         | 
| 137 | 
            +
              end
         | 
| 138 | 
            +
             | 
| 139 | 
            +
              def pick_color
         | 
| 140 | 
            +
                Term::ANSIColor::Attribute[
         | 
| 141 | 
            +
                  case @color
         | 
| 142 | 
            +
                  when Proc
         | 
| 143 | 
            +
                    @color.(@title)
         | 
| 144 | 
            +
                  when nil
         | 
| 145 | 
            +
                    cs = (21..226).select { |d|
         | 
| 146 | 
            +
                      Term::ANSIColor::Attribute[d].to_rgb_triple.to_hsl_triple.
         | 
| 147 | 
            +
                        lightness < 40
         | 
| 148 | 
            +
                    }
         | 
| 149 | 
            +
                    cs[ @title.bytes.reduce(0, :+) % cs.size ]
         | 
| 150 | 
            +
                  else
         | 
| 151 | 
            +
                    @color
         | 
| 152 | 
            +
                  end
         | 
| 153 | 
            +
                ]
         | 
| 154 | 
            +
              end
         | 
| 155 | 
            +
             | 
| 156 | 
            +
              def sleep_now
         | 
| 157 | 
            +
                sleep @sleep
         | 
| 158 | 
            +
              end
         | 
| 159 | 
            +
             | 
| 160 | 
            +
              def perform_display_diff
         | 
| 161 | 
            +
                @mutex.synchronize do
         | 
| 162 | 
            +
                  unless @old_display && @old_display.dimensions == @display.dimensions
         | 
| 163 | 
            +
                    @old_display = @display.dup.clear
         | 
| 164 | 
            +
                  end
         | 
| 165 | 
            +
                  perform @display - @old_display
         | 
| 166 | 
            +
                  @display, @old_display = @old_display.clear, @display
         | 
| 167 | 
            +
                  perform move_to(lines, columns)
         | 
| 168 | 
            +
                end
         | 
| 169 | 
            +
              end
         | 
| 170 | 
            +
             | 
| 171 | 
            +
             | 
| 172 | 
            +
              def normalize_value(value)
         | 
| 173 | 
            +
                case value
         | 
| 174 | 
            +
                when Float
         | 
| 175 | 
            +
                  value
         | 
| 176 | 
            +
                else
         | 
| 177 | 
            +
                  value.to_i
         | 
| 178 | 
            +
                end
         | 
| 179 | 
            +
              end
         | 
| 180 | 
            +
             | 
| 181 | 
            +
              def full_reset
         | 
| 182 | 
            +
                @mutex.synchronize do
         | 
| 183 | 
            +
                  perform reset, clear_screen, move_home, show_cursor
         | 
| 184 | 
            +
                  winsize = Tins::Terminal.winsize
         | 
| 185 | 
            +
                  @display     = Hackmac::Graph::Display.new(*winsize)
         | 
| 186 | 
            +
                  @old_display = Hackmac::Graph::Display.new(*winsize)
         | 
| 187 | 
            +
                  perform @display
         | 
| 188 | 
            +
                  @full_reset = false
         | 
| 189 | 
            +
                end
         | 
| 190 | 
            +
              end
         | 
| 191 | 
            +
             | 
| 192 | 
            +
              def install_handlers
         | 
| 193 | 
            +
                at_exit { full_reset }
         | 
| 194 | 
            +
                trap(:SIGWINCH) do
         | 
| 195 | 
            +
                  @full_reset = true
         | 
| 196 | 
            +
                  perform reset, clear_screen, move_home, 'Zzz…'
         | 
| 197 | 
            +
                end
         | 
| 198 | 
            +
              end
         | 
| 199 | 
            +
            end
         | 
| 200 | 
            +
             | 
| 201 | 
            +
            require 'hackmac/graph/display'
         | 
    
        data/lib/hackmac/version.rb
    CHANGED
    
    
    
        data/lib/hackmac.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: hackmac
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.4.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Florian Frank
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2023-05- | 
| 11 | 
            +
            date: 2023-05-28 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: gem_hadar
         | 
| @@ -150,6 +150,8 @@ extra_rdoc_files: | |
| 150 150 | 
             
            - lib/hackmac/config.rb
         | 
| 151 151 | 
             
            - lib/hackmac/disks.rb
         | 
| 152 152 | 
             
            - lib/hackmac/github_source.rb
         | 
| 153 | 
            +
            - lib/hackmac/graph.rb
         | 
| 154 | 
            +
            - lib/hackmac/graph/display.rb
         | 
| 153 155 | 
             
            - lib/hackmac/kext.rb
         | 
| 154 156 | 
             
            - lib/hackmac/kext_upgrader.rb
         | 
| 155 157 | 
             
            - lib/hackmac/oc.rb
         | 
| @@ -174,6 +176,8 @@ files: | |
| 174 176 | 
             
            - lib/hackmac/config.rb
         | 
| 175 177 | 
             
            - lib/hackmac/disks.rb
         | 
| 176 178 | 
             
            - lib/hackmac/github_source.rb
         | 
| 179 | 
            +
            - lib/hackmac/graph.rb
         | 
| 180 | 
            +
            - lib/hackmac/graph/display.rb
         | 
| 177 181 | 
             
            - lib/hackmac/hackmac.yml
         | 
| 178 182 | 
             
            - lib/hackmac/kext.rb
         | 
| 179 183 | 
             
            - lib/hackmac/kext_upgrader.rb
         |