hackmac 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|