hackmac 0.0.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 +7 -0
- data/.gitignore +9 -0
- data/Gemfile +5 -0
- data/README.md +0 -0
- data/Rakefile +23 -0
- data/VERSION +1 -0
- data/bin/efi +125 -0
- data/bin/gfxmon +168 -0
- data/hackmac.gemspec +45 -0
- data/lib/hackmac/disks.rb +32 -0
- data/lib/hackmac/kext.rb +49 -0
- data/lib/hackmac/plist.rb +18 -0
- data/lib/hackmac/search_ui.rb +87 -0
- data/lib/hackmac/version.rb +8 -0
- data/lib/hackmac.rb +10 -0
- metadata +138 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b290c529d2da09837d0a09dc98aa1f3d078da12e1700448e439eb792cf5ecc72
|
4
|
+
data.tar.gz: 820c27075b099d5e42a7dd49b0dc3ebab617b8301cc8201f3ae3f62dd3aeca58
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4e8247b2fcae940a075f4a195a046143ca2a40912d2ce61803f2b37c17afb34dc7588ad2764259bdf633091713e97e5d6f003a064d628e409b466e33cde3f17e
|
7
|
+
data.tar.gz: 20068b49a77392b8e933ee76731f43ed0f78cceded0f6e2fc98682a3372eac5c311f349aa9ebd857f63117bcc6309c6562a65717bfb8e678d1e8acdd671473c4
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# vim: set filetype=ruby et sw=2 ts=2:
|
2
|
+
|
3
|
+
require 'gem_hadar'
|
4
|
+
|
5
|
+
GemHadar do
|
6
|
+
name 'hackmac'
|
7
|
+
author 'Florian Frank'
|
8
|
+
email 'flori@ping.de'
|
9
|
+
homepage "http://github.com/flori/#{name}"
|
10
|
+
summary 'Some useful tools for working with a Hackintosh'
|
11
|
+
description 'This ruby gem provides Some useful tools for working with a Hackintosh.'
|
12
|
+
bindir 'bin'
|
13
|
+
executables Dir['bin/*'].map(&File.method(:basename))
|
14
|
+
test_dir 'tests'
|
15
|
+
ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', '.rvmrc', '.AppleDouble',
|
16
|
+
'tags', '.bundle', '.DS_Store', '.byebug_history'
|
17
|
+
readme 'README.md'
|
18
|
+
|
19
|
+
dependency 'tins', '~>1.14'
|
20
|
+
dependency 'term-ansicolor', '~>1.3'
|
21
|
+
dependency 'amatch'
|
22
|
+
dependency 'plist'
|
23
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
data/bin/efi
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'hackmac'
|
4
|
+
include Hackmac
|
5
|
+
require 'term/ansicolor'
|
6
|
+
class String
|
7
|
+
include Term::ANSIColor
|
8
|
+
end
|
9
|
+
|
10
|
+
def x(cmd, verbose: true)
|
11
|
+
prompt = cmd =~ /\A\s*sudo/ ? ?# : ?$
|
12
|
+
output = `#{cmd}`
|
13
|
+
if $?.success?
|
14
|
+
print "#{prompt} #{cmd}".green
|
15
|
+
puts verbose ? "" : " >/dev/null".yellow
|
16
|
+
else
|
17
|
+
print "#{prompt} #{cmd}".red
|
18
|
+
puts verbose ? "" : " >/dev/null".yellow
|
19
|
+
STDERR.puts "command #{cmd.inspect} failed with exit status #{$?.exitstatus}".on_red.white
|
20
|
+
end
|
21
|
+
if verbose
|
22
|
+
print output.italic
|
23
|
+
end
|
24
|
+
output
|
25
|
+
end
|
26
|
+
|
27
|
+
def clone(from:, to:)
|
28
|
+
print "Cloning from #{from} to #{to} now? (y/n) ".bold.yellow
|
29
|
+
if gets !~ /\Ay/i
|
30
|
+
return
|
31
|
+
end
|
32
|
+
x %{sudo mkdir -v "/Volumes/#{from}"}
|
33
|
+
x %{sudo mkdir -v "/Volumes/#{to}"}
|
34
|
+
begin
|
35
|
+
x %{sudo diskutil mount -mountPoint "/Volumes/#{from}" "#{from}"}
|
36
|
+
x %{sudo diskutil mount -mountPoint "/Volumes/#{to}" "#{to}"}
|
37
|
+
x %{rsync -nav --exclude ".*" --delete "/Volumes/#{from}/" "/Volumes/#{to}/"}
|
38
|
+
print "This will be copied/deleted. Really do it? (y/n) ".bold.yellow
|
39
|
+
if gets !~ /\Ay/i
|
40
|
+
puts " *** Interrupted.".bold.yellow
|
41
|
+
exit 1
|
42
|
+
end
|
43
|
+
x %{rsync -av --exclude ".*" --delete "/Volumes/#{from}/" "/Volumes/#{to}/"}
|
44
|
+
ensure
|
45
|
+
x %{sudo diskutil unmount "#{from}"}
|
46
|
+
x %{sudo diskutil unmount "#{to}"}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def dev
|
51
|
+
value = x(%{bdmesg}, verbose: false).lines.
|
52
|
+
find { |l| l =~ /SelfDevicePath=(.*)\r/ and break $1 }
|
53
|
+
uuid = value.split('\\').last[/(?:<?GPT,)([\h-]+)/, 1] or exit 1
|
54
|
+
x(%{partutil --search-uuid #{uuid}}).chomp
|
55
|
+
end
|
56
|
+
|
57
|
+
case command = ARGV.shift
|
58
|
+
when 'mount'
|
59
|
+
mdev = ARGV.shift || dev
|
60
|
+
x %{sudo diskutil mount "#{mdev}"}
|
61
|
+
when /\Aun?mount\z/
|
62
|
+
mdev = ARGV.shift || dev
|
63
|
+
x %{sudo diskutil unmount "#{mdev}"}
|
64
|
+
when 'clone'
|
65
|
+
from = ARGV.shift or fail "need from argument"
|
66
|
+
from == 'boot' and from = dev
|
67
|
+
to = ARGV.shift or fail "need to argument"
|
68
|
+
to == 'boot' and to = dev
|
69
|
+
from != to or fail "cloning only allowed from one partition to another"
|
70
|
+
clone from: from, to: to
|
71
|
+
when 'kext'
|
72
|
+
begin
|
73
|
+
mdev = ARGV.shift || dev
|
74
|
+
x %{sudo diskutil mount "#{mdev}"}
|
75
|
+
on_efi = Dir['/Volumes/EFI/EFI/CLOVER/kexts/Other/*.kext'].map { |path|
|
76
|
+
Kext.new(path: path)
|
77
|
+
}.sort_by(&:name)
|
78
|
+
on_le = Dir['/Library/Extensions/*.kext'].map { |path|
|
79
|
+
Kext.new(path: path)
|
80
|
+
}.sort_by(&:name)
|
81
|
+
puts 'EFI'.yellow.bold
|
82
|
+
on_efi.each do |kext|
|
83
|
+
puts kext.compare_to(on_le)
|
84
|
+
end
|
85
|
+
puts 'L/E'.yellow.bold
|
86
|
+
on_le.each do |kext|
|
87
|
+
puts kext.compare_to(on_efi)
|
88
|
+
end
|
89
|
+
ensure
|
90
|
+
x %{sudo diskutil umount "#{mdev}"}
|
91
|
+
end
|
92
|
+
when nil
|
93
|
+
disks = Disks.new
|
94
|
+
efis = []
|
95
|
+
disks.as_hash['AllDisksAndPartitions'].each_with_object([]) { |d, ps|
|
96
|
+
uuids = Array(d['Partitions']&.map { |p| p['DiskUUID'] }&.compact)
|
97
|
+
efis.concat uuids.
|
98
|
+
map { |uuid| DiskInfo.new(disk: uuid) }.
|
99
|
+
select { |di| di.as_hash['FilesystemType'] == 'msdos' }
|
100
|
+
}
|
101
|
+
efis.map!(&:as_hash)
|
102
|
+
efis.each do |e|
|
103
|
+
e['Booted'] = e['DeviceIdentifier'] == dev
|
104
|
+
e['Volumes'] =
|
105
|
+
ContainerDisk.new(disk: e['ParentWholeDisk'], limiter: 'internal').
|
106
|
+
as_hash['VolumesFromDisks']
|
107
|
+
end
|
108
|
+
efis.map!(&:sort).map!(&:to_h)
|
109
|
+
puts "Bootdisk information".bold.yellow, JSON.pretty_generate(
|
110
|
+
efis.map { |e| e.subhash(
|
111
|
+
'Bootable',
|
112
|
+
'Booted',
|
113
|
+
'DeviceIdentifier',
|
114
|
+
'DiskUUID',
|
115
|
+
'IORegistryEntryName',
|
116
|
+
'MountPoint',
|
117
|
+
'ParentWholeDisk',
|
118
|
+
'VolumeName',
|
119
|
+
'Volumes',
|
120
|
+
)
|
121
|
+
}
|
122
|
+
).bold
|
123
|
+
else
|
124
|
+
fail "don't know how to #{command}"
|
125
|
+
end
|
data/bin/gfxmon
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'tins'
|
4
|
+
include Tins::GO
|
5
|
+
require 'term/ansicolor'
|
6
|
+
include Term::ANSIColor
|
7
|
+
class String
|
8
|
+
include Term::ANSIColor
|
9
|
+
end
|
10
|
+
require 'hackmac'
|
11
|
+
include Hackmac
|
12
|
+
require 'amatch'
|
13
|
+
|
14
|
+
$opts = go 'c:g:n:jlh', defaults: { ?s => true, ?n => 10 }
|
15
|
+
|
16
|
+
def usage
|
17
|
+
puts <<~end
|
18
|
+
Usage: #{File.basename($0)} [OPTIONS]
|
19
|
+
|
20
|
+
OPTIONS are
|
21
|
+
|
22
|
+
-h this help
|
23
|
+
-l output GPU performance data as list
|
24
|
+
-j output GPU performance data as json
|
25
|
+
-n SECONDS measure every SECONDS
|
26
|
+
-g METRIC output graph for performance METRIC
|
27
|
+
-c COLOR output graph in this terminal COLOR (between 0 - 255)
|
28
|
+
|
29
|
+
end
|
30
|
+
0
|
31
|
+
end
|
32
|
+
|
33
|
+
def ps
|
34
|
+
`ioreg -l`.lines.find { |l|
|
35
|
+
if l =~ /"PerformanceStatistics" = {([^}]+)}/
|
36
|
+
break Hash[
|
37
|
+
$1.split(?,).map { |a|
|
38
|
+
a = a.split(?=)
|
39
|
+
[ a[0][1..-2], (Integer(a[1]) rescue a[1]) ]
|
40
|
+
}.sort_by { |name, _| name.downcase }
|
41
|
+
]
|
42
|
+
end
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def format_bytes(n, v)
|
47
|
+
if n =~ /bytes/i
|
48
|
+
Tins::Unit.format(v, format: '%.3f%U', unit: '')
|
49
|
+
else
|
50
|
+
v.to_s
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def list(ps)
|
55
|
+
max = ps.keys.max_by(&:size)&.size&.to_i
|
56
|
+
puts ps.map { |n, v|
|
57
|
+
("%-#{max}s" % n) + " " + ("%s" % format_bytes(n, v)).bold
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def choose_metric(ps)
|
62
|
+
case metric = $opts[?g]
|
63
|
+
when nil
|
64
|
+
ps_names = ps.keys
|
65
|
+
metric = SearchUI.new(
|
66
|
+
match: -> answer {
|
67
|
+
matcher = Amatch::PairDistance.new(answer.downcase)
|
68
|
+
matches = ps_names.map { |n| [ n, -matcher.similar(n.downcase) ] }.
|
69
|
+
select { |_, s| s < 0 }.sort_by(&:last).map(&:first)
|
70
|
+
matches.empty? and matches = ps_names
|
71
|
+
matches.first(Tins::Terminal.lines - 1)
|
72
|
+
},
|
73
|
+
query: -> _answer, matches, selector {
|
74
|
+
matches.each_with_index.
|
75
|
+
map { |m, i| i == selector ? m.on_blue : m } * ?\n
|
76
|
+
},
|
77
|
+
found: -> _answer, matches, selector {
|
78
|
+
matches[selector]
|
79
|
+
},
|
80
|
+
output: STDOUT
|
81
|
+
).start and return metric
|
82
|
+
else
|
83
|
+
ps.key?(metric) and return metric
|
84
|
+
end
|
85
|
+
fail "Metric #{metric} not known"
|
86
|
+
end
|
87
|
+
|
88
|
+
def display_graph
|
89
|
+
if metric = choose_metric(ps)
|
90
|
+
sleep_duration = [ 1, ($opts[?n] || 10).to_i ].max
|
91
|
+
data = []
|
92
|
+
print hide_cursor
|
93
|
+
at_exit do
|
94
|
+
print reset, clear_screen, move_home, show_cursor
|
95
|
+
end
|
96
|
+
trap(:SIGWINCH) {
|
97
|
+
lines, cols = Tins::Terminal.winsize
|
98
|
+
print clear_screen,
|
99
|
+
move_to(lines / 2, (cols - "Zzz…".size) / 2) { "Zzz…".italic }
|
100
|
+
}
|
101
|
+
loop do
|
102
|
+
print clear_screen
|
103
|
+
|
104
|
+
lines, cols = Tins::Terminal.winsize
|
105
|
+
|
106
|
+
as_title = -> t {
|
107
|
+
move_to(lines, (cols - t.size) / 2) { t.bold }
|
108
|
+
}
|
109
|
+
|
110
|
+
case value = ps[metric]
|
111
|
+
when Float
|
112
|
+
data << value
|
113
|
+
else
|
114
|
+
data << value.to_i
|
115
|
+
end
|
116
|
+
data = data.last(cols)
|
117
|
+
|
118
|
+
y_width = (data.max - data.min).to_f
|
119
|
+
if y_width == 0
|
120
|
+
print(
|
121
|
+
as_title.("#{metric} / #{sleep_duration}s"),
|
122
|
+
move_to(lines / 2, (cols - "no data".size) / 2) { "no data".italic }
|
123
|
+
)
|
124
|
+
sleep sleep_duration
|
125
|
+
print clear_screen
|
126
|
+
next
|
127
|
+
end
|
128
|
+
|
129
|
+
unless c = $opts[?c]
|
130
|
+
cs = (21..226).select { |d|
|
131
|
+
Term::ANSIColor::Attribute[d].to_rgb_triple.to_hsl_triple.
|
132
|
+
lightness < 40
|
133
|
+
}
|
134
|
+
c = cs[ metric.bytes.reduce(0, :+) % cs.size ]
|
135
|
+
end
|
136
|
+
color = Term::ANSIColor::Attribute[c]
|
137
|
+
color_light = color.to_rgb_triple.to_hsl_triple.lighten(15) rescue color
|
138
|
+
|
139
|
+
data.each_with_index do |value, x|
|
140
|
+
x = x + cols - data.size + 1
|
141
|
+
y = lines - (((value - data.min) * lines / y_width)).round + 1
|
142
|
+
y.upto(lines) do |iy|
|
143
|
+
print move_to(iy, x) { ' '.on_color(y == iy ? color : color_light) }
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
print(
|
148
|
+
as_title.("#{metric} #{format_bytes(metric, data.last)} / #{sleep_duration}s"),
|
149
|
+
move_home { format_bytes(metric, data.max).bold },
|
150
|
+
move_to_line(lines) { format_bytes(metric, data.min).bold }
|
151
|
+
)
|
152
|
+
|
153
|
+
sleep sleep_duration
|
154
|
+
end
|
155
|
+
end
|
156
|
+
rescue Interrupt
|
157
|
+
end
|
158
|
+
|
159
|
+
case
|
160
|
+
when $opts[?h]
|
161
|
+
exit usage
|
162
|
+
when $opts[?l]
|
163
|
+
list ps
|
164
|
+
when $opts[?j]
|
165
|
+
jj ps
|
166
|
+
else
|
167
|
+
display_graph
|
168
|
+
end
|
data/hackmac.gemspec
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# stub: hackmac 0.0.0 ruby lib
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "hackmac".freeze
|
6
|
+
s.version = "0.0.0"
|
7
|
+
|
8
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
9
|
+
s.require_paths = ["lib".freeze]
|
10
|
+
s.authors = ["Florian Frank".freeze]
|
11
|
+
s.date = "2019-12-18"
|
12
|
+
s.description = "This ruby gem provides Some useful tools for working with a Hackintosh.".freeze
|
13
|
+
s.email = "flori@ping.de".freeze
|
14
|
+
s.executables = ["gfxmon".freeze, "efi".freeze]
|
15
|
+
s.extra_rdoc_files = ["README.md".freeze, "lib/hackmac.rb".freeze, "lib/hackmac/disks.rb".freeze, "lib/hackmac/kext.rb".freeze, "lib/hackmac/plist.rb".freeze, "lib/hackmac/search_ui.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, "hackmac.gemspec".freeze, "lib/hackmac.rb".freeze, "lib/hackmac/disks.rb".freeze, "lib/hackmac/kext.rb".freeze, "lib/hackmac/plist.rb".freeze, "lib/hackmac/search_ui.rb".freeze, "lib/hackmac/version.rb".freeze]
|
17
|
+
s.homepage = "http://github.com/flori/hackmac".freeze
|
18
|
+
s.rdoc_options = ["--title".freeze, "Hackmac - Some useful tools for working with a Hackintosh".freeze, "--main".freeze, "README.md".freeze]
|
19
|
+
s.rubygems_version = "3.0.6".freeze
|
20
|
+
s.summary = "Some useful tools for working with a Hackintosh".freeze
|
21
|
+
|
22
|
+
if s.respond_to? :specification_version then
|
23
|
+
s.specification_version = 4
|
24
|
+
|
25
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
26
|
+
s.add_development_dependency(%q<gem_hadar>.freeze, ["~> 1.11.0"])
|
27
|
+
s.add_runtime_dependency(%q<tins>.freeze, ["~> 1.14"])
|
28
|
+
s.add_runtime_dependency(%q<term-ansicolor>.freeze, ["~> 1.3"])
|
29
|
+
s.add_runtime_dependency(%q<amatch>.freeze, [">= 0"])
|
30
|
+
s.add_runtime_dependency(%q<plist>.freeze, [">= 0"])
|
31
|
+
else
|
32
|
+
s.add_dependency(%q<gem_hadar>.freeze, ["~> 1.11.0"])
|
33
|
+
s.add_dependency(%q<tins>.freeze, ["~> 1.14"])
|
34
|
+
s.add_dependency(%q<term-ansicolor>.freeze, ["~> 1.3"])
|
35
|
+
s.add_dependency(%q<amatch>.freeze, [">= 0"])
|
36
|
+
s.add_dependency(%q<plist>.freeze, [">= 0"])
|
37
|
+
end
|
38
|
+
else
|
39
|
+
s.add_dependency(%q<gem_hadar>.freeze, ["~> 1.11.0"])
|
40
|
+
s.add_dependency(%q<tins>.freeze, ["~> 1.14"])
|
41
|
+
s.add_dependency(%q<term-ansicolor>.freeze, ["~> 1.3"])
|
42
|
+
s.add_dependency(%q<amatch>.freeze, [">= 0"])
|
43
|
+
s.add_dependency(%q<plist>.freeze, [">= 0"])
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'hackmac/plist'
|
2
|
+
|
3
|
+
module Hackmac
|
4
|
+
class DiskInfo
|
5
|
+
include Hackmac::Plist
|
6
|
+
|
7
|
+
def initialize(disk:)
|
8
|
+
@disk = disk
|
9
|
+
plist *(%w[ diskutil info -plist ] << disk)
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :disk
|
13
|
+
end
|
14
|
+
|
15
|
+
class Disks
|
16
|
+
include Hackmac::Plist
|
17
|
+
|
18
|
+
def initialize(limiter: nil, device: nil)
|
19
|
+
plist *(%w[ diskutil list -plist ] + [ limiter, device ].compact)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class ContainerDisk < Disks
|
24
|
+
def initialize(disk:, limiter: nil)
|
25
|
+
@disk = disk
|
26
|
+
device = `#{Shellwords.join(%w[ diskutil list ] << disk)}`.
|
27
|
+
lines.grep(/Apple_APFS/).first&.split(/\s+/)&.[](4)
|
28
|
+
|
29
|
+
super device: device, limiter: limiter
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/hackmac/kext.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'hackmac/plist'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
module Hackmac
|
5
|
+
class Kext
|
6
|
+
include Hackmac::Plist
|
7
|
+
|
8
|
+
def initialize(path:)
|
9
|
+
@path = Pathname.new(path) + 'Contents/Info.plist'
|
10
|
+
@plist = File.open(@path) { |f| ::Plist.parse_xml(f) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def identifier
|
14
|
+
as_hash['CFBundleIdentifier']
|
15
|
+
end
|
16
|
+
|
17
|
+
def name
|
18
|
+
as_hash['CFBundleName'] || File.basename(identifier)
|
19
|
+
end
|
20
|
+
|
21
|
+
def version
|
22
|
+
as_hash['CFBundleShortVersionString']
|
23
|
+
end
|
24
|
+
|
25
|
+
def inspect
|
26
|
+
"#<#{self.class}: #{to_s}>"
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
"#{name} #{version}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def find_matches(others)
|
34
|
+
candidates = others.select { |o| o.name == name }
|
35
|
+
candidates.group_by { |c| c.version == version }
|
36
|
+
end
|
37
|
+
|
38
|
+
def compare_to(others)
|
39
|
+
matches = find_matches others
|
40
|
+
if other = matches[false]&.first
|
41
|
+
"#{to_s.red} ⚡#{other.to_s.red}"
|
42
|
+
elsif other = matches[true]&.first
|
43
|
+
"#{to_s.green} = #{other.to_s.green}"
|
44
|
+
else
|
45
|
+
"#{to_s.yellow}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'plist'
|
2
|
+
require 'shellwords'
|
3
|
+
|
4
|
+
module Hackmac
|
5
|
+
module Plist
|
6
|
+
def plist(*cmd)
|
7
|
+
@plist = ::Plist.parse_xml(`#{Shellwords.join(cmd)}`)
|
8
|
+
end
|
9
|
+
|
10
|
+
def as_hash(*)
|
11
|
+
@plist.dup
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_json(*a)
|
15
|
+
as_hash.to_json(*a)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'term/ansicolor'
|
2
|
+
|
3
|
+
class Hackmac::SearchUI
|
4
|
+
include Term::ANSIColor
|
5
|
+
|
6
|
+
def initialize(
|
7
|
+
match:,
|
8
|
+
query:,
|
9
|
+
found:,
|
10
|
+
output: STDOUT,
|
11
|
+
prompt: 'Search? %s'
|
12
|
+
)
|
13
|
+
@match = match
|
14
|
+
@query = query
|
15
|
+
@found = found
|
16
|
+
@output = output
|
17
|
+
@prompt = prompt
|
18
|
+
@selector = 0
|
19
|
+
@max_selector = nil
|
20
|
+
@answer = ''
|
21
|
+
end
|
22
|
+
|
23
|
+
def start
|
24
|
+
@output.print reset
|
25
|
+
@matches = @match.(@answer)
|
26
|
+
@selector = [ 0, [ @selector, @matches.size - 1 ].min ].max
|
27
|
+
result = @query.(@answer, @matches, @selector)
|
28
|
+
@output.print clear_screen
|
29
|
+
@output.print move_home { ?\n + result }
|
30
|
+
loop do
|
31
|
+
@output.print move_home { @prompt % @answer }
|
32
|
+
case getc
|
33
|
+
when true
|
34
|
+
@output.print clear_screen, move_home, reset
|
35
|
+
if result = @found.(@answer, @matches, @selector)
|
36
|
+
return result
|
37
|
+
else
|
38
|
+
return nil
|
39
|
+
end
|
40
|
+
when false
|
41
|
+
return nil
|
42
|
+
end
|
43
|
+
@matches = @match.(@answer)
|
44
|
+
@selector = [ 0, [ @selector, @matches.size - 1 ].min ].max
|
45
|
+
result = @query.(@answer, @matches, @selector)
|
46
|
+
@output.print clear_screen
|
47
|
+
@output.print move_home { ?\n + result }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def getc
|
54
|
+
system 'stty raw -echo'
|
55
|
+
c = STDIN.getc
|
56
|
+
system 'stty cooked echo'
|
57
|
+
case c
|
58
|
+
when "\x03"
|
59
|
+
false
|
60
|
+
when "\e"
|
61
|
+
STDIN.getc == ?[ or return nil
|
62
|
+
STDIN.getc =~ /\A([AB])\z/ or return nil
|
63
|
+
if $1 == ?A
|
64
|
+
@selector -= 1
|
65
|
+
else
|
66
|
+
@selector += 1
|
67
|
+
end
|
68
|
+
nil
|
69
|
+
when ?\r
|
70
|
+
true
|
71
|
+
when "\x7f"
|
72
|
+
@selector = 0
|
73
|
+
@answer.chop!
|
74
|
+
nil
|
75
|
+
when "\v"
|
76
|
+
@selector = 0
|
77
|
+
@answer.clear
|
78
|
+
nil
|
79
|
+
when /\A[\x00-\x1f]\z/
|
80
|
+
nil
|
81
|
+
else
|
82
|
+
@selector = 0
|
83
|
+
@answer << c
|
84
|
+
nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/hackmac.rb
ADDED
metadata
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hackmac
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Florian Frank
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-12-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: gem_hadar
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.11.0
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.11.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: tins
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.14'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.14'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: term-ansicolor
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.3'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: amatch
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: plist
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: This ruby gem provides Some useful tools for working with a Hackintosh.
|
84
|
+
email: flori@ping.de
|
85
|
+
executables:
|
86
|
+
- gfxmon
|
87
|
+
- efi
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files:
|
90
|
+
- README.md
|
91
|
+
- lib/hackmac.rb
|
92
|
+
- lib/hackmac/disks.rb
|
93
|
+
- lib/hackmac/kext.rb
|
94
|
+
- lib/hackmac/plist.rb
|
95
|
+
- lib/hackmac/search_ui.rb
|
96
|
+
- lib/hackmac/version.rb
|
97
|
+
files:
|
98
|
+
- ".gitignore"
|
99
|
+
- Gemfile
|
100
|
+
- README.md
|
101
|
+
- Rakefile
|
102
|
+
- VERSION
|
103
|
+
- bin/efi
|
104
|
+
- bin/gfxmon
|
105
|
+
- hackmac.gemspec
|
106
|
+
- lib/hackmac.rb
|
107
|
+
- lib/hackmac/disks.rb
|
108
|
+
- lib/hackmac/kext.rb
|
109
|
+
- lib/hackmac/plist.rb
|
110
|
+
- lib/hackmac/search_ui.rb
|
111
|
+
- lib/hackmac/version.rb
|
112
|
+
homepage: http://github.com/flori/hackmac
|
113
|
+
licenses: []
|
114
|
+
metadata: {}
|
115
|
+
post_install_message:
|
116
|
+
rdoc_options:
|
117
|
+
- "--title"
|
118
|
+
- Hackmac - Some useful tools for working with a Hackintosh
|
119
|
+
- "--main"
|
120
|
+
- README.md
|
121
|
+
require_paths:
|
122
|
+
- lib
|
123
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
requirements: []
|
134
|
+
rubygems_version: 3.0.6
|
135
|
+
signing_key:
|
136
|
+
specification_version: 4
|
137
|
+
summary: Some useful tools for working with a Hackintosh
|
138
|
+
test_files: []
|