hackmac 1.8.2 → 1.8.3

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.
data/lib/hackmac/graph.rb CHANGED
@@ -2,31 +2,139 @@ require 'term/ansicolor'
2
2
  require 'tins'
3
3
  require 'digest/md5'
4
4
 
5
+ # A class that provides graphical display functionality for terminal-based data
6
+ # visualization
7
+ #
8
+ # The Graph class enables the creation of dynamic, real-time visualizations of
9
+ # data values within a terminal environment. It manages the rendering of
10
+ # graphical representations such as line charts or graphs, updating them
11
+ # continuously based on provided data sources. The class handles terminal
12
+ # control operations, including cursor positioning, color management, and
13
+ # screen clearing to ensure smooth visual updates. It also supports
14
+ # configuration of display parameters like title, formatting strategies for
15
+ # values, update intervals, and color schemes for different data series.
16
+ #
17
+ # @example
18
+ # graph = Hackmac::Graph.new(
19
+ # title: 'CPU Usage',
20
+ # value: ->(i) { rand(100) },
21
+ # format_value: :as_percent,
22
+ # sleep: 1,
23
+ # color: 33
24
+ # )
25
+ # graph.start
26
+ # # Starts the graphical display loop
27
+ #
28
+ # @example
29
+ # graph = Hackmac::Graph.new(
30
+ # title: 'Memory Usage',
31
+ # value: ->(i) { `vm_stat`.match(/Pages free: (\d+)/)[1].to_i },
32
+ # format_value: :as_bytes,
33
+ # sleep: 2
34
+ # )
35
+ # graph.start
36
+ # # Starts a memory usage graph with custom data source and formatting
5
37
  class Hackmac::Graph
6
38
  include Term::ANSIColor
7
39
 
8
- include\
40
+ # A module that provides various formatting methods for converting numeric
41
+ # values into human-readable strings with appropriate units and display
42
+ # formats.
43
+ #
44
+ # The Formatters module contains a collection of utility methods designed to
45
+ # transform raw numeric data into formatted strings that are more suitable
46
+ # for display purposes. These methods handle common formatting tasks such as
47
+ # converting byte measurements, frequency values, temperature readings, and
48
+ # percentages into clean, readable representations.
49
+ #
50
+ # Each formatter method in this module is intended to be used with data
51
+ # visualization or reporting scenarios where presenting numerical information
52
+ # in an easily understandable format is important. The module also includes
53
+ # specialized functionality for deriving consistent color values based on
54
+ # input strings, which can be useful for maintaining visual coherence when
55
+ # displaying multiple data series.
56
+ #
57
+ # @example
58
+ # include Hackmac::Graph::Formatters
59
+ #
60
+ # as_bytes(1024 * 1024) # => "1.000MB"
61
+ # as_hertz(2500000000) # => "2.500GHz"
62
+ # as_celsius(37.5) # => "37.5°"
63
+ # as_percent(95.7) # => "95.7%"
64
+ # as_default(42) # => "42"
9
65
  module Formatters
66
+ # The as_bytes method formats a numeric value into a human-readable byte
67
+ # representation
68
+ #
69
+ # This method takes a numeric input and converts it into a formatted string
70
+ # representing the value in bytes with appropriate binary prefixes (KB,
71
+ # MB, GB, etc.)
72
+ #
73
+ # @param value [ Numeric ] the numeric value to be formatted as bytes
74
+ #
75
+ # @return [ String ] the formatted byte representation with unit suffix
10
76
  def as_bytes(value)
11
77
  Tins::Unit.format(value, prefix: :uc, format: '%.3f%U', unit: 'B')
12
78
  end
13
79
 
80
+ # The as_hertz method formats a numeric value into a human-readable
81
+ # frequency representation
82
+ #
83
+ # This method takes a numeric input and converts it into a formatted string
84
+ # representing the value in hertz with appropriate metric prefixes (kHz,
85
+ # MHz, GHz, etc.)
86
+ #
87
+ # @param value [ Numeric ] the numeric frequency value to be formatted
88
+ #
89
+ # @return [ String ] the formatted frequency representation with unit suffix
14
90
  def as_hertz(value)
15
91
  Tins::Unit.format(value, prefix: :uc, format: '%.3f%U', unit: 'Hz')
16
92
  end
17
93
 
94
+ # The as_celsius method formats a temperature value with a degree symbol
95
+ #
96
+ # This method takes a numeric temperature value and returns a string
97
+ # representation with the degree Celsius symbol appended to it
98
+ #
99
+ # @param value [ Numeric ] the temperature value to be formatted
100
+ #
101
+ # @return [ String ] the temperature value formatted with a degree Celsius symbol
18
102
  def as_celsius(value)
19
103
  "#{value}°"
20
104
  end
21
105
 
106
+ # The as_percent method formats a numeric value as a percentage string
107
+ #
108
+ # This method takes a numeric input and returns a string representation
109
+ # with a percent sign appended to it, providing a simple way to format
110
+ # numeric values as percentages for display purposes
111
+ #
112
+ # @param value [ Numeric ] the numeric value to be formatted as a percentage
113
+ #
114
+ # @return [ String ] the numeric value formatted as a percentage string
22
115
  def as_percent(value)
23
116
  "#{value}%"
24
117
  end
25
118
 
119
+ # The as_default method converts a value to its string representation
120
+ #
121
+ # This method takes any input value and converts it to a string using the to_s method
122
+ # It serves as a fallback formatting option when no specific formatting is required
123
+ #
124
+ # @param value [ Object ] the value to be converted to a string
125
+ #
126
+ # @return [ String ] the string representation of the input value
26
127
  def as_default(value)
27
128
  value.to_s
28
129
  end
29
130
 
131
+ # The derive_color_from_string method calculates a color value based on the
132
+ # input string by generating an MD5 hash and selecting from a predefined
133
+ # set of dark colors
134
+ #
135
+ # @param string [ String ] the input string used to derive the color value
136
+ #
137
+ # @return [ Integer ] the derived color value from the set of dark ANSI attributes
30
138
  def derive_color_from_string(string)
31
139
  cs = (21..226).select { |d|
32
140
  Term::ANSIColor::Attribute[d].to_rgb_triple.to_hsl_triple.
@@ -38,7 +146,23 @@ class Hackmac::Graph
38
146
 
39
147
  self
40
148
  end
41
-
149
+ include Formatters
150
+
151
+ # The initialize method sets up a Graph instance by configuring its display
152
+ # parameters and internal state
153
+ #
154
+ # This method configures the graph visualization with title, value provider,
155
+ # formatting options, update interval, and color settings. It initializes
156
+ # internal data structures for storing historical values and manages
157
+ # synchronization through a mutex for thread-safe operations.
158
+ #
159
+ # @param title [ String ] the title to display at the bottom of the graph
160
+ # @param value [ Proc ] a proc that takes an index and returns a numeric value for plotting
161
+ # @param format_value [ Proc, Symbol, nil ] formatting strategy for displaying values
162
+ # @param sleep [ Numeric ] time in seconds between updates
163
+ # @param color [ Integer, Proc, nil ] color index or proc to determine color dynamically
164
+ #
165
+ # @raise [ ArgumentError ] if the sleep parameter is negative
42
166
  def initialize(
43
167
  title:,
44
168
  value: -> i { 0 },
@@ -57,12 +181,28 @@ class Hackmac::Graph
57
181
  @mutex = Mutex.new
58
182
  end
59
183
 
184
+ # The start method initiates the graphical display process by setting up
185
+ # signal handlers, performing an initial terminal reset, and entering the
186
+ # main update loop
187
+ #
188
+ # This method serves as the entry point for starting the graph visualization
189
+ # functionality. It configures the necessary signal handlers for graceful
190
+ # shutdown and terminal resizing, performs an initial full reset of the
191
+ # display state, and then begins the continuous loop that updates and renders
192
+ # graphical data.
60
193
  def start
61
194
  install_handlers
62
195
  full_reset
63
196
  start_loop
64
197
  end
65
198
 
199
+ # The stop method terminates the graphical display process by performing a
200
+ # full reset and setting the continue flag to false
201
+ #
202
+ # This method serves as the shutdown mechanism for the graph visualization
203
+ # functionality. It ensures that all display resources are properly cleaned
204
+ # up and the terminal state is restored to its original condition before
205
+ # stopping the continuous update loop.
66
206
  def stop
67
207
  full_reset
68
208
  @continue = false
@@ -70,6 +210,16 @@ class Hackmac::Graph
70
210
 
71
211
  private
72
212
 
213
+ # The start_loop method executes a continuous loop to update and display
214
+ # graphical data
215
+ #
216
+ # This method manages the main execution loop for rendering graphical
217
+ # representations of data values over time. It initializes display state,
218
+ # processes incoming data, calculates visual representations, and handles
219
+ # terminal updates while respecting configured timing intervals.
220
+ #
221
+ # It continuously updates the display and handles data processing in a loop
222
+ # until explicitly stopped.
73
223
  def start_loop
74
224
  full_reset
75
225
  color = pick_color
@@ -120,23 +270,60 @@ class Hackmac::Graph
120
270
  end
121
271
 
122
272
  def perform(*a)
123
- print *a
273
+ print(*a)
124
274
  end
125
275
 
276
+ # The columns method returns the number of columns in the display
277
+ #
278
+ # This method provides access to the horizontal dimension of the graphical
279
+ # display by returning the total number of columns available for rendering
280
+ # content
281
+ #
282
+ # @return [ Integer ] the number of columns (characters per line) in the display object
126
283
  def columns
127
284
  @display.columns
128
285
  end
129
286
 
287
+ # The lines method returns the number of lines in the display
288
+ #
289
+ # This method provides access to the vertical dimension of the graphical
290
+ # display by returning the total number of rows available for rendering
291
+ # content
292
+ #
293
+ # @return [ Integer ] the number of lines (rows) in the display object
130
294
  def lines
131
295
  @display.lines
132
296
  end
133
297
 
298
+ # The data reader method provides access to the data attribute that was set
299
+ # during object initialization.
300
+ #
301
+ # This method returns the value of the data instance variable, which
302
+ # typically contains structured information that has been processed or
303
+ # collected by the object.
304
+ #
305
+ # @return [ Array<Object>, Hash, nil ] the data value stored in the instance variable, or nil if not set
134
306
  attr_reader :data
135
307
 
308
+ # The sleep_duration method returns a string representation of the configured
309
+ # sleep interval with the 's' suffix appended to indicate seconds.
310
+ #
311
+ # @return [ String ] a formatted string containing the sleep duration in seconds
136
312
  def sleep_duration
137
313
  "#{@sleep}s"
138
314
  end
139
315
 
316
+ # The format_value method processes a given value using the configured
317
+ # formatting strategy
318
+ #
319
+ # This method applies the appropriate formatting to a value based on the
320
+ # @format_value instance variable configuration It supports different
321
+ # formatting approaches including custom Proc objects, Symbol-based method
322
+ # calls, and default formatting
323
+ #
324
+ # @param value [ Object ] the value to be formatted according to the configured strategy
325
+ #
326
+ # @return [ String ] the formatted string representation of the input value
140
327
  def format_value(value)
141
328
  case @format_value
142
329
  when Proc
@@ -148,6 +335,28 @@ class Hackmac::Graph
148
335
  end
149
336
  end
150
337
 
338
+ # The pick_color method determines and returns an ANSI color attribute based
339
+ # on the configured color setting
340
+ #
341
+ # This method evaluates the @color instance variable to decide how to select
342
+ # a color attribute. If @color is a Proc, it invokes the proc with the @title
343
+ # to determine the color. If @color is nil, it derives a color from the title
344
+ # string. Otherwise, it uses the @color value directly as an index into the
345
+ # ANSI color attributes.
346
+ #
347
+ # @return [ Term::ANSIColor::Attribute ] the selected color attribute object
348
+ def pick_color
349
+ Term::ANSIColor::Attribute[
350
+ case @color
351
+ when Proc
352
+ @color.(@title)
353
+ when nil
354
+ derive_color_from_string(@title)
355
+ else
356
+ @color
357
+ end
358
+ ]
359
+ end
151
360
  def pick_color
152
361
  Term::ANSIColor::Attribute[
153
362
  case @color
@@ -161,6 +370,14 @@ class Hackmac::Graph
161
370
  ]
162
371
  end
163
372
 
373
+ # The sleep_now method calculates and executes a sleep duration based on the
374
+ # configured sleep time and elapsed time since start
375
+ #
376
+ # This method determines how long to sleep by calculating the difference
377
+ # between the configured sleep interval and the time elapsed since the last
378
+ # operation started. If no start time is recorded, it uses the full
379
+ # configured sleep duration. The method ensures that negative sleep durations
380
+ # are not used by taking the maximum of the calculated duration and zero.
164
381
  def sleep_now
165
382
  duration = if @start
166
383
  [ @sleep - (Time.now - @start).to_f, 0 ].max
@@ -170,6 +387,22 @@ class Hackmac::Graph
170
387
  sleep duration
171
388
  end
172
389
 
390
+ # The perform_display_diff method calculates and displays the difference
391
+ # between the current and previous display states to update only the changed
392
+ # portions of the terminal output
393
+ #
394
+ # This method synchronizes access to shared display resources using a mutex,
395
+ # then compares the current display with the previous state to determine what
396
+ # needs updating. It handles dimension mismatches by resetting the old
397
+ # display, computes the visual difference, and outputs only the modified
398
+ # portions to reduce terminal update overhead
399
+ #
400
+ # When the DEBUG_BYTESIZE environment variable is set, it also outputs
401
+ # debugging information about the size of the diff and the time elapsed since
402
+ # the last debug output
403
+ #
404
+ # @return [ void ] Returns nothing but performs terminal output operations
405
+ # and updates internal display state
173
406
  def perform_display_diff
174
407
  @mutex.synchronize do
175
408
  unless @old_display && @old_display.dimensions == @display.dimensions
@@ -191,6 +424,18 @@ class Hackmac::Graph
191
424
  end
192
425
 
193
426
 
427
+ # The normalize_value method converts a value to its appropriate numeric
428
+ # representation
429
+ #
430
+ # This method takes an input value and normalizes it to either a Float or
431
+ # Integer type depending on its original form. If the value is already a
432
+ # Float, it is returned as-is. For all other types, the method attempts to
433
+ # convert the value to an integer using to_i
434
+ #
435
+ # @param value [ Object ] the value to be normalized
436
+ #
437
+ # @return [ Float, Integer ] the normalized numeric value as either a Float
438
+ # or Integer
194
439
  def normalize_value(value)
195
440
  case value
196
441
  when Float
@@ -200,6 +445,15 @@ class Hackmac::Graph
200
445
  end
201
446
  end
202
447
 
448
+ # The full_reset method performs a complete reset of the display and terminal
449
+ # state
450
+ #
451
+ # This method synchronizes access to shared resources using a mutex, then
452
+ # executes a series of terminal control operations to reset the terminal
453
+ # state, clear the screen, move the cursor to the home position, and make the
454
+ # cursor visible. It also initializes new display objects with the current
455
+ # terminal dimensions and updates the internal
456
+ # display state.
203
457
  def full_reset
204
458
  @mutex.synchronize do
205
459
  perform reset, clear_screen, move_home, show_cursor
@@ -211,6 +465,12 @@ class Hackmac::Graph
211
465
  end
212
466
  end
213
467
 
468
+ # The install_handlers method sets up signal handlers for graceful shutdown
469
+ # and terminal resize handling
470
+ #
471
+ # This method configures two signal handlers: one for the exit hook that
472
+ # performs a full reset, and another for the SIGWINCH signal that handles
473
+ # terminal resize events by setting a flag and displaying a sleeping message
214
474
  def install_handlers
215
475
  at_exit { full_reset }
216
476
  trap(:SIGWINCH) do
data/lib/hackmac/ioreg.rb CHANGED
@@ -1,11 +1,33 @@
1
1
  require 'hashie'
2
2
 
3
3
  module Hackmac
4
+ # A class that provides access to IORegistry information through plist
5
+ # parsing
6
+ #
7
+ # The IOReg class interfaces with macOS's IORegistry system to retrieve and
8
+ # parse hardware-related information for a specified key. It executes the
9
+ # ioreg command with appropriate flags to fetch XML data, processes this data
10
+ # into a structured hash format, and makes it available for querying through
11
+ # dynamic method calls.
12
+ #
13
+ # @example
14
+ # ioreg = Hackmac::IOReg.new(key: 'IOPowerManagement')
15
+ # # Provides access to power management information through method calls
4
16
  class IOReg
5
17
  include Hackmac::Plist
6
-
18
+ # The initialize method sets up an IOReg instance by executing a system
19
+ # command to retrieve hardware registry information for a specific key.
20
+ #
21
+ # This method constructs and runs a shell command using the ioreg utility
22
+ # to fetch detailed information about a specified hardware key from the
23
+ # IOService registry. It processes the XML output, extends the resulting
24
+ # hash with deep find capabilities, and stores the largest matching result
25
+ # set in the instance variable.
26
+ #
27
+ # @param key [ String ] the hardware registry key to search for in the
28
+ # IOService tree
7
29
  def initialize(key:)
8
- plist *(%w[ioreg -a -p IOService -r -k ] << key)
30
+ plist(*(%w[ioreg -a -p IOService -r -k ] << key))
9
31
  @plist.extend Hashie::Extensions::DeepFind
10
32
  @plist = @plist.deep_find_all(key).max_by(&:size)
11
33
  end
data/lib/hackmac/kext.rb CHANGED
@@ -3,10 +3,33 @@ require 'pathname'
3
3
  require 'tins/string_version'
4
4
 
5
5
  module Hackmac
6
+
7
+ # A class that represents a kernel extension (kext) and provides access to
8
+ # its metadata and remote version information
9
+ #
10
+ # The Kext class encapsulates the functionality for working with macOS kernel
11
+ # extensions, including loading their Info.plist files, extracting metadata
12
+ # such as identifiers and versions, and determining whether newer versions
13
+ # are available from remote sources
14
+ #
15
+ # @example
16
+ # kext = Hackmac::Kext.new(path: '/path/to/MyKext.kext')
17
+ # # Provides access to kext metadata through method calls
6
18
  class Kext
7
19
  include Hackmac::Plist
8
20
  include Tins::StringVersion
9
21
 
22
+ # The initialize method sets up a Kext instance by loading and parsing its
23
+ # Info.plist file
24
+ #
25
+ # This method takes a path to a kext directory and optionally a
26
+ # configuration object, then reads the Info.plist file within the kext's
27
+ # Contents directory to extract metadata about the kernel extension. The
28
+ # plist data is parsed and stored for later access through dynamic method
29
+ # calls.
30
+ #
31
+ # @param path [ String ] the filesystem path to the kext directory
32
+ # @param config [ Object, nil ] optional configuration object that may provide source information
10
33
  def initialize(path:, config: nil)
11
34
  @path = path
12
35
  info = Pathname.new(@path) + 'Contents/Info.plist'
@@ -14,16 +37,49 @@ module Hackmac
14
37
  @config = config
15
38
  end
16
39
 
40
+ # The path reader method provides access to the path attribute that was set
41
+ # during object initialization.
42
+ #
43
+ # This method returns the value of the path instance variable, which
44
+ # typically represents the filesystem path associated with the object.
45
+ #
46
+ # @return [ String ] the path value stored in the instance variable
17
47
  attr_reader :path
18
48
 
49
+ # The identifier method retrieves the bundle identifier from the kext's
50
+ # Info.plist file
51
+ #
52
+ # This method accesses the CFBundleIdentifier key from the parsed plist
53
+ # data of a kernel extension, providing the unique identifier that
54
+ # distinguishes this particular kext within the system
55
+ #
56
+ # @return [ String ] the bundle identifier of the kernel extension
57
+ # @return [ nil ] returns nil if the CFBundleIdentifier key is not present in the plist
19
58
  def identifier
20
59
  CFBundleIdentifier()
21
60
  end
22
61
 
62
+ # The name method retrieves the display name for the kernel extension
63
+ #
64
+ # This method attempts to return the CFBundleName value from the kext's
65
+ # Info.plist file and falls back to using the basename of the bundle
66
+ # identifier if that value is not present
67
+ #
68
+ # @return [ String ] the human-readable name of the kernel extension
69
+ # @return [ nil ] returns nil if neither CFBundleName nor identifier is available
23
70
  def name
24
71
  CFBundleName() || File.basename(identifier)
25
72
  end
26
73
 
74
+ # The version method retrieves and caches the version identifier from the
75
+ # kext's Info.plist file
76
+ #
77
+ # This method attempts to extract the CFBundleShortVersionString value from
78
+ # the parsed plist data and convert it into a Version object for proper
79
+ # semantic versioning comparison. If the version string is not a valid
80
+ # semantic version, it stores the raw string instead.
81
+ #
82
+ # @return [ Tins::StringVersion, String, nil ] the version object or string if found, nil otherwise
27
83
  def version
28
84
  unless @version
29
85
  if version = CFBundleShortVersionString()
@@ -37,6 +93,18 @@ module Hackmac
37
93
  @version
38
94
  end
39
95
 
96
+ # The remote_kext method retrieves or creates a remote source object for a
97
+ # kext
98
+ #
99
+ # This method attempts to return an existing cached remote kext source or
100
+ # constructs a new one based on the configuration source for this kext. It
101
+ # supports both GitHub-based sources and direct URL downloads, determining
102
+ # the appropriate source type from the configuration and creating the
103
+ # corresponding source object.
104
+ #
105
+ # @return [ Hackmac::GithubSource, Hackmac::URLDownload, nil ] returns the remote
106
+ # source object if a configuration source exists, or nil if no source is
107
+ # configured or the kext has no associated configuration
40
108
  def remote_kext
41
109
  return @remote_kext if @remote_kext
42
110
  if @config
@@ -58,14 +126,35 @@ module Hackmac
58
126
  end
59
127
  end
60
128
 
129
+ # The remote_version method retrieves the version identifier from the
130
+ # remote kext source
131
+ #
132
+ # This method accesses the cached remote kext source object and returns its
133
+ # version information if available. It uses the safe navigation operator to
134
+ # avoid errors when the remote kext source has not been initialized or does
135
+ # not have version data
136
+ #
137
+ # @return [ Tins::StringVersion, String, nil ] the version object or string from
138
+ # the remote source, or nil if no remote source is available or has no version
139
+ # information
61
140
  def remote_version
62
141
  remote_kext&.version
63
142
  end
64
143
 
144
+ # The inspect method returns a string representation of the object
145
+ # that includes its class name and string value
146
+ #
147
+ # @return [ String ] a formatted string containing the object's class name
148
+ # and its string representation
65
149
  def inspect
66
150
  "#<#{self.class}: #{to_s}>"
67
151
  end
68
152
 
153
+ # The to_s method returns a string representation of the object by
154
+ # combining its name and version attributes into a single space-separated
155
+ # string.
156
+ #
157
+ # @return [ String ] a formatted string containing the name and version separated by a space
69
158
  def to_s
70
159
  "#{name} #{version}"
71
160
  end
@@ -3,16 +3,54 @@ require 'find'
3
3
  require 'pathname'
4
4
 
5
5
  module Hackmac
6
+ # A class that handles the upgrade process for kernel extensions (kexts)
7
+ #
8
+ # The KextUpgrader class manages the workflow for upgrading macOS kernel extensions
9
+ # by checking remote version availability, downloading new versions, and performing
10
+ # file system operations to replace existing kext files after user confirmation
11
+ #
12
+ # @example
13
+ # upgrader = Hackmac::KextUpgrader.new(path: '/path/to/kext', config: config_obj)
14
+ # upgrader.perform
15
+ # # Executes the kext upgrade process in a temporary directory context
6
16
  class KextUpgrader
7
17
  include FileUtils
8
18
  include Hackmac::AssetTools
9
19
 
20
+ # The initialize method sets up a KextUpgrader instance by storing the
21
+ # provided path, configuration, and force flag.
22
+ #
23
+ # This method takes the necessary parameters to configure the kext
24
+ # upgrader, including the filesystem path to the kext, the configuration
25
+ # object that defines source information, and a force flag that determines
26
+ # whether upgrades should be performed even when the remote version is not
27
+ # newer than the local version.
28
+ #
29
+ # @param path [ String ] the filesystem path to the kext directory that
30
+ # needs upgrading
31
+ # @param config [ Object ] the configuration object containing source
32
+ # information for the kext
33
+ # @param force [ TrueClass, FalseClass ] flag indicating whether to force
34
+ # upgrade even if remote version is not newer
10
35
  def initialize(path:, config:, force: false)
11
36
  @path, @config, @force = path, config, force
12
37
  end
13
38
 
14
39
  public
15
40
 
41
+ # The perform method executes the kext upgrade process by isolating the
42
+ # operation in a temporary directory
43
+ #
44
+ # This method handles the complete workflow for upgrading a kernel
45
+ # extension, including checking for remote version availability,
46
+ # downloading and decompressing the new version, identifying target
47
+ # installation paths, and performing the actual file replacement after user
48
+ # confirmation
49
+ #
50
+ # @return [ void ] Returns nothing but performs file system operations and
51
+ # user interaction
52
+ # @raise [ RuntimeError ] raised when a remote download fails or when no
53
+ # source is defined for the kext
16
54
  def perform
17
55
  isolate do |dir|
18
56
  kext = Kext.new(path: @path, config: @config)