hardware_information 1.0.83

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.
Files changed (30) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +94 -0
  3. data/bin/hardware_information +12 -0
  4. data/doc/README.gen +47 -0
  5. data/hardware_information.gemspec +38 -0
  6. data/lib/hardware_information/class/hardware_information.rb +1048 -0
  7. data/lib/hardware_information/css/project.css +3 -0
  8. data/lib/hardware_information/gui/gtk2/purchased_hardware/purchased_hardware.rb +34 -0
  9. data/lib/hardware_information/gui/gtk2/show_input_devices/show_input_devices.rb +34 -0
  10. data/lib/hardware_information/gui/gtk3/mounted_harddiscs/mounted_harddiscs.rb +103 -0
  11. data/lib/hardware_information/gui/gtk3/purchased_hardware/purchased_hardware.rb +34 -0
  12. data/lib/hardware_information/gui/gtk3/show_input_devices/show_input_devices.rb +34 -0
  13. data/lib/hardware_information/gui/libui/mounted_harddiscs/mounted_harddiscs.rb +88 -0
  14. data/lib/hardware_information/gui/shared_code/mounted_harddiscs/mounted_harddiscs_module.rb +107 -0
  15. data/lib/hardware_information/gui/shared_code/purchased_hardware/purchased_hardware_module.rb +293 -0
  16. data/lib/hardware_information/gui/shared_code/show_input_devices/show_input_devices_module.rb +187 -0
  17. data/lib/hardware_information/misc/purchased_hardware/README.md +7 -0
  18. data/lib/hardware_information/misc/purchased_hardware/purchased_hardware.rb +169 -0
  19. data/lib/hardware_information/monitor/README.md +6 -0
  20. data/lib/hardware_information/monitor/monitor.rb +36 -0
  21. data/lib/hardware_information/project/project.rb +29 -0
  22. data/lib/hardware_information/version/version.rb +19 -0
  23. data/lib/hardware_information/www/embeddable_interface.rb +52 -0
  24. data/lib/hardware_information/www/my_hardware.cgi +7 -0
  25. data/lib/hardware_information/www/my_hardware.rb +498 -0
  26. data/lib/hardware_information/www/my_hardware_for_sinatra.rb +65 -0
  27. data/lib/hardware_information/yaml/colours_for_the_hardware_information_project.yml +30 -0
  28. data/lib/hardware_information/yaml/usb_errors/usb_errors.yml +2 -0
  29. data/lib/hardware_information.rb +7 -0
  30. metadata +91 -0
@@ -0,0 +1,1048 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ # === HardwareInformation
6
+ #
7
+ # This class will show some information about the local computer system,
8
+ # e. g. hardware information, via colours.
9
+ # =========================================================================== #
10
+ # require 'hardware_information'
11
+ # =========================================================================== #
12
+ class HardwareInformation # === HardwareInformation
13
+
14
+ require 'hardware_information/version/version.rb'
15
+ require 'hardware_information/project/project.rb'
16
+
17
+ # ========================================================================= #
18
+ # === N
19
+ # ========================================================================= #
20
+ N = "\n"
21
+
22
+ # ========================================================================= #
23
+ # === ERROR_LINE
24
+ # ========================================================================= #
25
+ ERROR_LINE = '2>&1'
26
+
27
+ # ========================================================================= #
28
+ # === LEFT_PADDING
29
+ #
30
+ # How many characters to pad on the left side. Used for the
31
+ # header_content() method.
32
+ # ========================================================================= #
33
+ LEFT_PADDING = 26
34
+
35
+ # ========================================================================= #
36
+ # === MAIN_DEFAULT_RJUST
37
+ # ========================================================================= #
38
+ MAIN_DEFAULT_RJUST = 48
39
+
40
+ # ========================================================================= #
41
+ # === CPUINFO_LOCATION
42
+ #
43
+ # This constants stores where cpuinfo is kept. Will work only on
44
+ # Linux, I think.
45
+ # ========================================================================= #
46
+ CPUINFO_LOCATION = '/proc/cpuinfo'
47
+
48
+ # ========================================================================= #
49
+ # === PROC_MEMINFO
50
+ # ========================================================================= #
51
+ PROC_MEMINFO = '/proc/meminfo'
52
+
53
+ # ========================================================================= #
54
+ # === FILE_COLOURS_FOR_THE_HARDWARE_PROJECT
55
+ # ========================================================================= #
56
+ FILE_COLOURS_FOR_THE_HARDWARE_PROJECT =
57
+ "#{PROJECT_YAML_DIRECTORY}colours_for_the_hardware_information_project.yml"
58
+
59
+ # ========================================================================= #
60
+ # === HardwareInformation.kb_to_mb(i)
61
+ # ========================================================================= #
62
+ def self.kb_to_mb(i)
63
+ (
64
+ i.gsub(/ kB/,'').to_i / 1024
65
+ ).to_s+ ' MB'
66
+ end
67
+
68
+ # ========================================================================= #
69
+ # === HardwareInformation.is_on_windows?
70
+ # ========================================================================= #
71
+ def self.is_on_windows?
72
+ if RUBY_PLATFORM.include?('win') or # if on windows.
73
+ RUBY_PLATFORM.include?('mingw')
74
+ return true
75
+ end
76
+ return false
77
+ end
78
+
79
+ # ========================================================================= #
80
+ # === LSCPU
81
+ #
82
+ # The `lscpu` command may fail, which is why it has to be put into
83
+ # a begin/rescue clause.
84
+ # ========================================================================= #
85
+ if is_on_windows?
86
+ LSCPU = nil
87
+ else
88
+ begin
89
+ LSCPU = `lscpu`.split("\n")
90
+ rescue Errno::ENOENT
91
+ puts 'No binary called lscpu could be found.'
92
+ end
93
+ end
94
+
95
+ # ========================================================================= #
96
+ # === CPUINFO
97
+ #
98
+ # We must first check whether the target location actually does happen
99
+ # to exist.
100
+ # ========================================================================= #
101
+ _ = CPUINFO_LOCATION
102
+ if File.exist? _
103
+ CPUINFO = File.read(_)
104
+ else
105
+ CPUINFO = nil
106
+ end
107
+
108
+ # ========================================================================= #
109
+ # === SPLITTED_CPUINFO
110
+ # ========================================================================= #
111
+ if CPUINFO
112
+ SPLITTED_CPUINFO = CPUINFO.split(N)
113
+ begin
114
+ LSPCI = `lspci`
115
+ rescue # Must rescue here because lspci might not be available.
116
+ LSPCI = nil
117
+ end
118
+ end
119
+
120
+ # ========================================================================= #
121
+ # === DATASET_FROM_PROC_MEMINFO
122
+ # ========================================================================= #
123
+ if File.exist? PROC_MEMINFO
124
+ DATASET_FROM_PROC_MEMINFO = File.readlines(PROC_MEMINFO)
125
+ _ = DATASET_FROM_PROC_MEMINFO.select {|entry|
126
+ entry.include? 'MemTotal'
127
+ }.first.strip.split(':').last.strip
128
+ # ======================================================================= #
129
+ # We discard all but the gigs for RAM.
130
+ # ======================================================================= #
131
+ _ = (_.gsub(/ kB/,'').to_i / 1024).to_s+ ' MB'
132
+ else
133
+ DATASET_FROM_PROC_MEMINFO = nil
134
+ end
135
+
136
+ # ========================================================================= #
137
+ # === RAM_AVAILABLE
138
+ # ========================================================================= #
139
+ RAM_AVAILABLE = _
140
+
141
+ if DATASET_FROM_PROC_MEMINFO
142
+ _ = DATASET_FROM_PROC_MEMINFO.select {|entry|
143
+ entry.include? 'MemFree'
144
+ }.first.strip.split(':').last.strip #.gsub(/ kB/,'').to_i / 1024).to_s+ ' MB'
145
+ # ======================================================================= #
146
+ # === RAM_AVAILABLE_FREE
147
+ # ======================================================================= #
148
+ RAM_AVAILABLE_FREE = kb_to_mb(_)
149
+ end
150
+
151
+ # ========================================================================= #
152
+ # === initialize
153
+ # ========================================================================= #
154
+ def initialize(
155
+ run_already = true
156
+ )
157
+ reset
158
+ case run_already
159
+ when :do_not_run_yet
160
+ run_already = false
161
+ end
162
+ set_run_already(
163
+ run_already
164
+ )
165
+ run if run_already
166
+ end
167
+
168
+ # ========================================================================= #
169
+ # === reset (reset tag)
170
+ # ========================================================================= #
171
+ def reset
172
+ # ======================================================================= #
173
+ # === @string
174
+ # ======================================================================= #
175
+ @string = ''.dup
176
+ # ======================================================================= #
177
+ # === @default_colour
178
+ # ======================================================================= #
179
+ @default_colour = green?
180
+ # ======================================================================= #
181
+ # === @default_padding
182
+ #
183
+ # This variable denotes the leading padding. That padding will be
184
+ # prepended to the output.
185
+ # ======================================================================= #
186
+ @default_padding = ' '.dup # 2 spaces since as of December 2022.
187
+ # ======================================================================= #
188
+ # === @use_colours
189
+ # ======================================================================= #
190
+ @use_colours = true # If true we use ANSI colours.
191
+ # ======================================================================= #
192
+ # === @use_colon_as_delimiter
193
+ # ======================================================================= #
194
+ @use_colon_as_delimiter = true # If true we use colon as delimiter.
195
+ # ======================================================================= #
196
+ # === @hash_use_these_colours
197
+ #
198
+ # Next we will load the internal .yml file, if it exists.
199
+ # ======================================================================= #
200
+ @hash_use_these_colours = {}
201
+ if File.exist? FILE_COLOURS_FOR_THE_HARDWARE_PROJECT
202
+ require 'yaml'
203
+ @hash_use_these_colours.update(
204
+ YAML.load_file(FILE_COLOURS_FOR_THE_HARDWARE_PROJECT)
205
+ )
206
+ else # else use a hardcoded approach.
207
+ @hash_use_these_colours[:filesize_of_the_harddisc] = :orchid
208
+ @hash_use_these_colours[:file_system_type] = :steelblue
209
+ end
210
+ set_commandline_mode # Default.
211
+ end
212
+
213
+ # ========================================================================= #
214
+ # === make_line
215
+ #
216
+ # The first argument to this method should be the title that will
217
+ # be displayed.
218
+ #
219
+ # The second argument should show the content towards that argument.
220
+ # ========================================================================= #
221
+ def make_line(
222
+ title, content
223
+ )
224
+ title = title.dup if title.frozen?
225
+ use_this_colour_for_change = bold_teal?
226
+ use_this_colour_to_revert = @default_colour # First a copy.
227
+ title << ': ' if @use_colon_as_delimiter
228
+ title = default_ljust(title)
229
+ content = default_rjust(content)
230
+ # ======================================================================= #
231
+ # === Handle blocks next
232
+ #
233
+ # The passed block can modify the variable called content. This
234
+ # will happen after the various padding-operations above.
235
+ # ======================================================================= #
236
+ if block_given?
237
+ yielded = yield
238
+ case yielded
239
+ when nil
240
+ # Pas through.
241
+ else # Else, use colours.
242
+ if use_colours?
243
+ content = COLOURS.send(yielded, content)
244
+ end
245
+ end
246
+ end
247
+ string = ''.dup
248
+ string << use_this_colour_for_change if use_colours?
249
+ string << title
250
+ string << use_this_colour_to_revert if use_colours?
251
+ string = string.ljust(40)
252
+ if content.is_a? Array
253
+ _ string
254
+ content.each {|line| _ " #{line}" }
255
+ else
256
+ string << content
257
+ _ string
258
+ end
259
+ end
260
+
261
+ # ========================================================================= #
262
+ # === start_the_sinatra_interface
263
+ #
264
+ # To invoke this method, do:
265
+ #
266
+ # hardi --sinatra
267
+ #
268
+ # ========================================================================= #
269
+ def start_the_sinatra_interface
270
+ require 'hardware_information/www/my_hardware_for_sinatra.rb'
271
+ HardwareInformation::SinatraMyHardware.start_sinatra_interface
272
+ end
273
+
274
+ # ========================================================================= #
275
+ # === menu (menu tag)
276
+ #
277
+ # Commandline-arguments, e. g. ARGV, will be passed into this menu
278
+ # interface.
279
+ # ========================================================================= #
280
+ def menu(
281
+ i = nil
282
+ )
283
+ if i
284
+ if i.is_a? Array
285
+ i.each {|entry| menu(entry) }
286
+ else
287
+ case i # case tag
288
+ # =================================================================== #
289
+ # === hardi --sinatra
290
+ # =================================================================== #
291
+ when /^-?-?sinatra$/
292
+ start_the_sinatra_interface
293
+ # =================================================================== #
294
+ # === hardi --disable-colours
295
+ # =================================================================== #
296
+ when /^-?-?disable(-|_)?colou?rs$/,
297
+ /^-?-?no(-|_)?colou?rs$/
298
+ disable_colours
299
+ end
300
+ end
301
+ end
302
+ end
303
+
304
+ # ========================================================================= #
305
+ # === set_run_already
306
+ # ========================================================================= #
307
+ def set_run_already(i)
308
+ @run_already = i
309
+ end
310
+
311
+ # ========================================================================= #
312
+ # === pad?
313
+ # ========================================================================= #
314
+ def pad?
315
+ @default_padding
316
+ end
317
+
318
+ # ========================================================================= #
319
+ # === append_newline
320
+ # ========================================================================= #
321
+ def append_newline
322
+ add N
323
+ end
324
+
325
+ # ========================================================================= #
326
+ # === report_result
327
+ # ========================================================================= #
328
+ def report_result
329
+ e string?
330
+ end
331
+
332
+ # ========================================================================= #
333
+ # === string?
334
+ # ========================================================================= #
335
+ def string?
336
+ @string
337
+ end; alias string string? # === string
338
+
339
+ # ========================================================================= #
340
+ # === set_commandline_mode
341
+ # ========================================================================= #
342
+ def set_commandline_mode
343
+ @mode = :commandline
344
+ end
345
+
346
+ # ========================================================================= #
347
+ # === set_web_mode
348
+ # ========================================================================= #
349
+ def set_web_mode
350
+ @mode = :web
351
+ end
352
+
353
+ # ========================================================================= #
354
+ # === default_ljust
355
+ # ========================================================================= #
356
+ def default_rjust(i)
357
+ if i.is_a? Array # We do not handle Arrays.
358
+ i
359
+ else
360
+ i.to_s.rjust(MAIN_DEFAULT_RJUST)
361
+ end
362
+ end
363
+
364
+ # ========================================================================= #
365
+ # === _ (_ tag)
366
+ #
367
+ # This method, as a shortcut, makes use of the method called add(),
368
+ # but it will also append a newline to the given input and support
369
+ # colours (if given as argument).
370
+ # ========================================================================= #
371
+ def _(i, optional_colour = nil)
372
+ if optional_colour and use_colours? # Add colours only if needed.
373
+ if optional_colour.is_a? Symbol
374
+ i = ::Colours.send(optional_colour, i)
375
+ else
376
+ i = optional_colour+i+rev
377
+ end
378
+ end
379
+ add "#{i}#{N}" # We try it with mandatory newline for now.
380
+ end
381
+
382
+ # ========================================================================= #
383
+ # === add_title
384
+ # ========================================================================= #
385
+ def add_title
386
+ optional_colour = nil
387
+ if use_colours?
388
+ if Object.const_defined? :Colours # User has the colours gem installed.
389
+ optional_colour = :mediumslateblue
390
+ else
391
+ optional_colour = green?
392
+ end
393
+ end
394
+ _ "#{N}Hardware Information"\
395
+ " "\
396
+ "💻#{N}", optional_colour
397
+ end
398
+
399
+ # ========================================================================= #
400
+ # === colourize_filesize_of_the_harddisc
401
+ # ========================================================================= #
402
+ def colourize_filesize_of_the_harddisc(i)
403
+ COLOURS.send(
404
+ @hash_use_these_colours[:filesize_of_the_harddisc],
405
+ i
406
+ )
407
+ end
408
+
409
+ # ========================================================================= #
410
+ # === colourize_file_system_type
411
+ # ========================================================================= #
412
+ def colourize_file_system_type(i)
413
+ COLOURS.send(
414
+ @hash_use_these_colours[:file_system_type],
415
+ i
416
+ )
417
+ end
418
+
419
+ # ========================================================================= #
420
+ # === colourize_n_percent_occupied
421
+ # ========================================================================= #
422
+ def colourize_n_percent_occupied(i)
423
+ COLOURS.send(
424
+ @hash_use_these_colours[:n_percent_occupied],
425
+ i
426
+ )
427
+ end
428
+
429
+ # ========================================================================= #
430
+ # === colourize_highlighted_content
431
+ # ========================================================================= #
432
+ def colourize_highlighted_content(i)
433
+ COLOURS.send(
434
+ @hash_use_these_colours[:highlighted_content],
435
+ i
436
+ )
437
+ end
438
+
439
+ # ========================================================================= #
440
+ # === colourize_via_regular_colour
441
+ #
442
+ # Do note that this is presently hardcoded to the "thistle" colour.
443
+ # Unsure whether to allow the user more customization here, so for
444
+ # the time being this remains hardcoded.
445
+ # ========================================================================= #
446
+ def colourize_via_regular_colour(i)
447
+ COLOURS.send(
448
+ :thistle,
449
+ i
450
+ )
451
+ end
452
+
453
+ # ========================================================================= #
454
+ # === append_output_generated_via_lsblk
455
+ #
456
+ # Typical output generated via lsblk may be like this:
457
+ #
458
+ # NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
459
+ # sda 8:0 0 2.7T 0 disk
460
+ # ├─sda1 8:1 0 1M 0 part
461
+ # └─sda2 8:2 0 2.7T 0 part /
462
+ # sr0 11:0 1 1024M 0 rom
463
+ #
464
+ # ========================================================================= #
465
+ def append_output_generated_via_lsblk
466
+ _ = ''.dup
467
+ # ======================================================================== #
468
+ # Next we will display/obtain more information, via df.
469
+ # ======================================================================== #
470
+ extended_information = `df -T`.split(N)
471
+ result = `lsblk`.strip.split(N).map {|line| " #{line}" }
472
+ result.each {|entry|
473
+ # ===================================================================== #
474
+ # Modify the input.
475
+ # ===================================================================== #
476
+ if entry.include? ' /'
477
+ # =================================================================== #
478
+ # These entries will be colourized. Note that the first part may
479
+ # look like this: "└─sda2"
480
+ #
481
+ # " └─sda2 8:2 0 2.7T 0 part /"
482
+ #
483
+ # =================================================================== #
484
+ splitted = entry.split(' ')
485
+ # =================================================================== #
486
+ # The root_entry may look like this:
487
+ #
488
+ # /dev/sda2 ext4 2883218608 529813416 2206875608 20% /
489
+ #
490
+ # =================================================================== #
491
+ selection = extended_information.select {|line|
492
+ last = line.split(' ').last
493
+ last == '/' or last.include?('USB')
494
+ }
495
+ if selection
496
+ selection = selection.select {|inner_line|
497
+ inner_line.end_with? splitted[-1]
498
+ }
499
+ if selection.is_a?(Array) and selection.first
500
+ selection = selection.first.split(' ')
501
+ end
502
+ end
503
+ splitted[-1] = colourize_highlighted_content(splitted[-1].ljust(12)) # ← The last part.
504
+ splitted[0] = colourize_highlighted_content(" #{splitted[0]}") # ← The first part.
505
+ splitted[1] = colourize_via_regular_colour(splitted[1].strip.ljust(4).rjust(6))
506
+ splitted[2] = colourize_via_regular_colour(" #{splitted[2].strip.rjust(2)}")
507
+ splitted[3] = colourize_filesize_of_the_harddisc(splitted[3].strip.rjust(5).ljust(6)) # ← The size of the harddisc.
508
+ splitted[4] = colourize_via_regular_colour(splitted[4].strip.ljust(2).rjust(3))
509
+ splitted[5] = colourize_via_regular_colour(splitted[5].strip)
510
+ file_system_type = selection[1]
511
+ n_percent_occupied = selection[5]
512
+ # =================================================================== #
513
+ # /dev/sda2 ext4 2883218608 529753916 2206935108 20% /"]
514
+ # =================================================================== #
515
+ splitted = splitted.join(' ')
516
+ unless entry.include? '/boot/' # ← Don't show information for /boot/ entries.
517
+ splitted << colourize_file_system_type(" (#{file_system_type})")
518
+ splitted << colourize_n_percent_occupied(" (#{n_percent_occupied} used)")
519
+ end
520
+ entry = splitted
521
+ else # Else we only do a slightly simpler colourization-part.
522
+ splitted = entry.split(' ')
523
+ splitted[0] = colourize_via_regular_colour(" #{splitted[0].ljust(6)}") # ← The first part.
524
+ splitted[1] = colourize_via_regular_colour(splitted[1].strip.ljust(4).rjust(6))
525
+ splitted[2] = colourize_via_regular_colour(" #{splitted[2].strip.rjust(2)}")
526
+ splitted[3] = colourize_filesize_of_the_harddisc(splitted[3].strip.rjust(5).ljust(6)) # ← The size of the harddisc.
527
+ splitted[4] = colourize_via_regular_colour(splitted[4].strip.ljust(2).rjust(3))
528
+ splitted[5] = colourize_via_regular_colour(splitted[5].strip)
529
+ if splitted[6] and (splitted[6] == '[SWAP]')
530
+ splitted[6] = royalblue(splitted[6])
531
+ end
532
+ entry = splitted.join(' ')
533
+ entry = colourize_via_regular_colour(entry)
534
+ end
535
+ _ << "#{entry}\n" # Now we can append this.
536
+ }
537
+ # ======================================================================= #
538
+ # Add two newlines too, for slightly more readable output.
539
+ # ======================================================================= #
540
+ _ << "#{N}#{N}"
541
+ add _
542
+ end
543
+
544
+ # ========================================================================= #
545
+ # === default_ljust
546
+ # ========================================================================= #
547
+ def default_ljust(i)
548
+ i.to_s.ljust(15)
549
+ end
550
+ begin
551
+ require 'colours'
552
+ include ::Colours
553
+ rescue LoadError; end
554
+
555
+ # ========================================================================= #
556
+ # === COLOURS
557
+ # ========================================================================= #
558
+ COLOURS = ::Colours
559
+
560
+ # ========================================================================= #
561
+ # === green?
562
+ # ========================================================================= #
563
+ def green?
564
+ COLOURS::GREEN
565
+ end
566
+
567
+ # ========================================================================= #
568
+ # === bold_teal?
569
+ # ========================================================================= #
570
+ def bold_teal?
571
+ COLOURS::BOLD_TEAL
572
+ end
573
+
574
+ # ========================================================================= #
575
+ # === use_colours?
576
+ # ========================================================================= #
577
+ def use_colours?
578
+ @use_colours
579
+ end
580
+
581
+ # ========================================================================= #
582
+ # === enable_colours
583
+ # ========================================================================= #
584
+ def enable_colours
585
+ @use_colours = true
586
+ end
587
+
588
+ # ========================================================================= #
589
+ # === disable_colours
590
+ # ========================================================================= #
591
+ def disable_colours
592
+ @use_colours = false
593
+ end
594
+
595
+ # ========================================================================= #
596
+ # === thistle
597
+ # ========================================================================= #
598
+ def thistle(i)
599
+ return COLOURS.thistle(i) if use_colours?
600
+ return i
601
+ end
602
+
603
+ # ========================================================================= #
604
+ # === royalblue
605
+ # ========================================================================= #
606
+ def royalblue(i)
607
+ return COLOURS.royalblue(i) if use_colours?
608
+ return i
609
+ end
610
+
611
+ # ========================================================================= #
612
+ # === steelblue
613
+ # ========================================================================= #
614
+ def steelblue(i)
615
+ return COLOURS.steelblue(i) if use_colours?
616
+ return i
617
+ end
618
+
619
+ # ========================================================================= #
620
+ # === rev
621
+ # ========================================================================= #
622
+ def rev
623
+ if use_colours?
624
+ COLOURS.rev
625
+ else
626
+ ''
627
+ end
628
+ end
629
+
630
+ # ========================================================================= #
631
+ # === add_audio_information (audio tag)
632
+ # ========================================================================= #
633
+ def add_audio_information
634
+ audio_device = `aplay -l`.scan(/card.+$/).first
635
+ make_line(pad?+'Audio Device', N+(pad? * 2)+audio_device.to_s)
636
+ end
637
+
638
+ # ========================================================================= #
639
+ # === add (add tag)
640
+ # ========================================================================= #
641
+ def add(i)
642
+ @string << i
643
+ end
644
+
645
+ # ========================================================================= #
646
+ # === obtain_information_about_the_wireless_card
647
+ #
648
+ # This method will display information about the wireless card (WLAN
649
+ # device), should it exist.
650
+ # ========================================================================= #
651
+ def obtain_information_about_the_wireless_card
652
+ result = `lspci #{ERROR_LINE}`
653
+ if result and result.is_a?(String) and !result.empty?
654
+ splitted = result.split("\n")
655
+ selection = splitted.select {|entry|
656
+ entry.include? 'Wireless'
657
+ }
658
+ if selection and !selection.empty?
659
+ _ = selection.first.split(':').last.to_s
660
+ make_line("#{pad?}WLAN", _) { :mediumspringgreen }
661
+ end
662
+ end
663
+ end
664
+
665
+ # ========================================================================= #
666
+ # === obtain_virtualization
667
+ #
668
+ # This method call may fail, depending on the output of the LSCPU
669
+ # command, hence why this check has to be a bit more complicated.
670
+ # ========================================================================= #
671
+ def obtain_virtualization
672
+ result = LSCPU.grep(/Virtualization:/)
673
+ if result
674
+ result = result.first.split(':').last.strip
675
+ make_line(pad?+'Virtualization', result) { :mediumseagreen }
676
+ end
677
+ end
678
+
679
+ # ========================================================================= #
680
+ # === obtain_information_about_the_GPU
681
+ # ========================================================================= #
682
+ def obtain_information_about_the_GPU
683
+ make_line(pad?+'GPU',
684
+ return_information_about_the_GPU
685
+ ) { :mediumpurple }
686
+ end
687
+
688
+ # ========================================================================= #
689
+ # === return_information_about_the_GPU
690
+ #
691
+ # This method will return information about the GPU in use on the given
692
+ # computer system.
693
+ #
694
+ # This may be similar to a String such as:
695
+ #
696
+ # GPU: AMD ATI Radeon R7 Graphics
697
+ #
698
+ # ========================================================================= #
699
+ def return_information_about_the_GPU
700
+ result = `lspci #{ERROR_LINE}`.strip
701
+ if result and result.include?('VGA compatible controller')
702
+ result = result.split(N).select {|line|
703
+ line.include? 'VGA compatible controller'
704
+ }.first
705
+ # ===================================================================== #
706
+ # Work on:
707
+ #
708
+ # VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Kaveri [Radeon R7 Graphics]"
709
+ #
710
+ # ===================================================================== #
711
+ result = result.split('. [').last.
712
+ delete('[]').tr('/',' ')
713
+ end
714
+ return result
715
+ end
716
+
717
+ # ========================================================================= #
718
+ # === assumed_path_to_dmidecode?
719
+ # ========================================================================= #
720
+ def assumed_path_to_dmidecode?
721
+ _ = '/usr/bin/dmidecode'
722
+ unless File.exist? _
723
+ if File.exist?('/usr/sbin/dmidecode')
724
+ _ = '/usr/sbin/dmidecode'
725
+ end
726
+ end
727
+ return _
728
+ end
729
+
730
+ # ========================================================================= #
731
+ # === obtain_firmware_information
732
+ #
733
+ # Note that this functionality depends on the binary called "lshw".
734
+ # ========================================================================= #
735
+ def obtain_firmware_information
736
+ result = `lshw #{ERROR_LINE}`
737
+ if result.include? 'lshw: command not found'
738
+ e grey('(Note that the binary ')+
739
+ steelblue('lshw')+
740
+ grey(' could not be found.)')
741
+ end
742
+ if result and !result.include?('command not found')
743
+ # ===================================================================== #
744
+ # See: https://rubular.com/r/Uf4XqmbZW3atCy
745
+ # ===================================================================== #
746
+ regex =
747
+ /description: Motherboard\s+product: (.+)\s+vendor: (.+)\s+[.:0-9a-zA-Z\n ]+\*-firmware[.:0-9a-zA-Z\n ]+version: (\d{0,4}[0-9.]+)\s+date: (\d{1,2}.+)/
748
+ result =~ regex
749
+ motherboard = $1.to_s.dup
750
+ motherboard_vendor = $2.to_s.dup
751
+ bios_version = $3.to_s.dup
752
+ bios_release = $4.to_s.dup
753
+ end
754
+ if (bios_version.nil? or bios_version.empty?) and result.include?('command not found')
755
+ # ===================================================================== #
756
+ # Try dmidecode in this case.
757
+ # ===================================================================== #
758
+ result = `#{assumed_path_to_dmidecode?} #{ERROR_LINE}`
759
+ if result
760
+ result = result.split("\n").select {|line| line.include? 'BIOS Revision: ' }
761
+ if result and result.is_a?(Array)
762
+ result = result.first.to_s
763
+ bios_version = result.split(':').last.strip if result.include?(':')
764
+ end
765
+ end
766
+ end
767
+ # ======================================================================= #
768
+ # Show some more information next, in particular the BIOS.
769
+ # ======================================================================= #
770
+ make_line(pad?+'Motherboard vendor', motherboard_vendor) { :olivedrab }
771
+ make_line(pad?+'Motherboard', motherboard)
772
+ make_line(pad?+'BIOS version', bios_version)
773
+ make_line(pad?+'BIOS released on', bios_release)
774
+ end
775
+
776
+ # ========================================================================= #
777
+ # === obtain_vendor_id
778
+ # ========================================================================= #
779
+ def obtain_vendor_id
780
+ result = LSCPU.grep(/Vendor ID:/).first.split(':').last.strip
781
+ make_line(pad?+'Vendor ID', result) { :mediumseagreen }
782
+ end
783
+
784
+ # ========================================================================= #
785
+ # === obtain_n_cores
786
+ #
787
+ # Return how many cores that machine has.
788
+ #
789
+ # "nproc" will return the number we seek here.
790
+ # ========================================================================= #
791
+ def obtain_n_cores
792
+ make_line(pad?+'n CPU cores',
793
+ # `nproc --all`.strip
794
+ `nproc`.strip
795
+ ) { :lightgreen }
796
+ end
797
+
798
+ # ========================================================================= #
799
+ # === obtain_ram (ram tag)
800
+ # ========================================================================= #
801
+ def obtain_ram
802
+ make_line(pad?+'RAM (max)', RAM_AVAILABLE) { :orangered }
803
+ end
804
+
805
+ # ========================================================================= #
806
+ # === obtain_ram_free
807
+ # ========================================================================= #
808
+ def obtain_ram_free
809
+ make_line(pad?+'RAM (free)', RAM_AVAILABLE_FREE) { :orangered }
810
+ end
811
+
812
+ # ========================================================================= #
813
+ # === obtain_ram_type
814
+ # ========================================================================= #
815
+ def obtain_ram_type
816
+ use_this_string = 'unknown'
817
+ regex_to_use = /Bank Locator: (BANK 1)$\n\s+Type: (.+)$/ # See: https://rubular.com/r/naJf6OIlcx8aWI
818
+ _ = `dmidecode -t memory`
819
+ _ =~ regex_to_use
820
+ potentially_new_string = $2.to_s.dup
821
+ if potentially_new_string and !potentially_new_string.empty?
822
+ use_this_string = potentially_new_string
823
+ end
824
+ make_line(pad?+'RAM (type)', use_this_string) { :deeppink }
825
+ end
826
+
827
+ # ========================================================================= #
828
+ # === obtain_swap_size (swap tag)
829
+ # ========================================================================= #
830
+ def obtain_swap_size
831
+ _ = DATASET_FROM_PROC_MEMINFO.grep(/SwapTotal:/).first.
832
+ split(' ').last.strip.upcase
833
+ make_line(pad?+'SwapTotal', _) { :springgreen }
834
+ end
835
+
836
+ # ========================================================================= #
837
+ # === obtain_system_bogomips
838
+ #
839
+ # BogoMIPS measure CPU speed.
840
+ # ========================================================================= #
841
+ def obtain_system_bogomips
842
+ make_line pad?+'BogoMIPS',
843
+ SPLITTED_CPUINFO.select {|line|
844
+ line.include? 'bogomips'
845
+ }.first.split(':')[1].strip
846
+ end
847
+
848
+ # ========================================================================= #
849
+ # === obtain_pci_information
850
+ # ========================================================================= #
851
+ def obtain_pci_information
852
+ array_fetch_these_types = %w(
853
+ SMBus Audio IDE VGA
854
+ Memory Controller
855
+ )
856
+ results = []
857
+ if LSPCI
858
+ LSPCI.split(N).each {|line|
859
+ array_fetch_these_types.each { |inner_line|
860
+ results << line if line.include? inner_line
861
+ }
862
+ }
863
+ make_line pad?+'PCI Devices', results
864
+ end
865
+ end
866
+
867
+ # ========================================================================= #
868
+ # === obtain_chip_mhz
869
+ # ========================================================================= #
870
+ def obtain_chip_mhz
871
+ make_line pad?+'Chip MHzx',
872
+ SPLITTED_CPUINFO.select {|line|
873
+ line.include? 'cpu MHz'
874
+ }.first.split(':')[1].strip
875
+ end
876
+
877
+ # ========================================================================= #
878
+ # === obtain_cache_size
879
+ # ========================================================================= #
880
+ def obtain_cache_size
881
+ make_line pad?+'Cache Size',
882
+ SPLITTED_CPUINFO.select {|line|
883
+ line.include? 'cache size'
884
+ }.first.split(':')[1].strip
885
+ end
886
+
887
+ # ========================================================================= #
888
+ # === obtain_cpu_model
889
+ # ========================================================================= #
890
+ def obtain_cpu_model
891
+ result = SPLITTED_CPUINFO.select {|line|
892
+ line.include? 'model name'
893
+ }.first.split(':')[1].strip
894
+ make_line pad?+'Model', result
895
+ end
896
+
897
+ # ========================================================================= #
898
+ # === obtain_byte_order
899
+ # ========================================================================= #
900
+ def obtain_byte_order
901
+ result = LSCPU.grep(/Byte Order:/).first.split(':').last.strip
902
+ make_line pad?+'Byte Order', result
903
+ end
904
+
905
+ # ========================================================================= #
906
+ # === obtain_cpu_family
907
+ # ========================================================================= #
908
+ def obtain_cpu_family
909
+ result = LSCPU.grep(/CPU family:/).first.split(':').last.strip
910
+ make_line pad?+'CPU family', result
911
+ end
912
+
913
+ # ========================================================================= #
914
+ # === obtain_model
915
+ # ========================================================================= #
916
+ def obtain_model
917
+ result = LSCPU.grep(/Model:/).first.split(':').last.strip
918
+ make_line pad?+'Model', result
919
+ end
920
+
921
+ # ========================================================================= #
922
+ # === obtain_cpu_op_modes
923
+ # ========================================================================= #
924
+ def obtain_cpu_op_modes
925
+ result = LSCPU.grep(/CPU op-mode/).first.split(':').last.strip
926
+ make_line(pad?+'CPU op-mode(s)', result)
927
+ end
928
+
929
+ # ========================================================================= #
930
+ # === obtain_linux_kernel_version
931
+ #
932
+ # This method should return a String, such as '4.14.4'.
933
+ # ========================================================================= #
934
+ def obtain_linux_kernel_version
935
+ result = `uname -r`.strip
936
+ make_line(pad?+'Linux kernel version', result)
937
+ end
938
+
939
+ # ========================================================================= #
940
+ # === obtain_architecture
941
+ # ========================================================================= #
942
+ def obtain_architecture
943
+ result = LSCPU.grep(/Architecture:/).first.split(':').last.strip
944
+ make_line(pad?+'Architecture', result) { :violet }
945
+ end
946
+
947
+ # ========================================================================= #
948
+ # === obtain_the_computer_name
949
+ # ========================================================================= #
950
+ def obtain_the_computer_name
951
+ result = `uname -n`.strip
952
+ make_line(pad?+'Computer name', result) { :cadetblue }
953
+ end
954
+
955
+ # ========================================================================= #
956
+ # === find_out_the_amount_of_processors
957
+ # ========================================================================= #
958
+ def find_out_the_amount_of_processors
959
+ data = CPUINFO.scan(/cpu cores\t: (\d+)\n/).flatten.map(&:to_i).sum.to_i
960
+ make_line(pad?+'Processors', data) { :slateblue }
961
+ end
962
+
963
+ require 'hardware_information/monitor/monitor.rb'
964
+ # ========================================================================= #
965
+ # === obtain_information_about_the_monitor
966
+ #
967
+ # This method will show the display-size of the monitor at hand.
968
+ # ========================================================================= #
969
+ def obtain_information_about_the_monitor
970
+ make_line(
971
+ "#{pad?}Monitor resolution",
972
+ ::HardwareInformation.return_the_monitor_resolution
973
+ ) { :mediumspringgreen }
974
+ end
975
+
976
+ # ========================================================================= #
977
+ # === try_to_obtain_information_about_the_mouse
978
+ #
979
+ # This method assumes that a USB mouse is in use. This will evidently
980
+ # not always be the case. But if it is the case then this class
981
+ # will show more information pertaining to the mouse.
982
+ # ========================================================================= #
983
+ def try_to_obtain_information_about_the_mouse
984
+ _ = `lsusb`.split("\n").select {|line| line.include? 'Optical Mouse' }
985
+ unless _.empty?
986
+ _ = _.first.to_s # "Bus 001 Device 002: ID 046d:c050 Logitech, Inc. RX 250 Optical Mouse"
987
+ use_this_regex = /:[a-z]\d{1,3} /
988
+ if _ =~ use_this_regex
989
+ _ = _.split(use_this_regex).last.to_s
990
+ make_line(
991
+ "#{pad?}Mouse (Pointer device)",
992
+ _
993
+ ) { :mediumspringgreen }
994
+ end
995
+ end
996
+ end
997
+
998
+ # ========================================================================= #
999
+ # === run (run tag)
1000
+ # ========================================================================= #
1001
+ def run
1002
+ add_title
1003
+ obtain_the_computer_name # === The computer name
1004
+ obtain_architecture # === Architecture
1005
+ obtain_cpu_model # === The CPU model, such as "AMD"
1006
+ obtain_cpu_op_modes # === CPU op-modes
1007
+ obtain_n_cores # === n CPU cores
1008
+ find_out_the_amount_of_processors # === Amount of processors
1009
+ obtain_vendor_id # === Vendor ID
1010
+ obtain_virtualization # === Virtualization
1011
+ obtain_linux_kernel_version # === The Linux kernel version
1012
+ obtain_ram # === Amount of RAM
1013
+ obtain_ram_free # === Amount of free RAM
1014
+ obtain_ram_type # === Show the type of RAM e. g. DDR4.
1015
+ obtain_swap_size # === SwapTotal
1016
+ obtain_chip_mhz # === Chip MHzx
1017
+ obtain_cache_size
1018
+ obtain_system_bogomips # === BogoMIPS
1019
+ obtain_byte_order
1020
+ obtain_cpu_family
1021
+ obtain_model # === Model
1022
+ obtain_information_about_the_GPU # === Show the GPU in use
1023
+ obtain_information_about_the_monitor # === Gather information about the monitor (Monitor resolution)
1024
+ obtain_information_about_the_wireless_card # === Wireless card
1025
+ obtain_firmware_information # === Firmware Information
1026
+ try_to_obtain_information_about_the_mouse # === Show information about the mouse
1027
+ obtain_pci_information
1028
+ add_audio_information # === Show the audio device
1029
+ append_newline
1030
+ append_output_generated_via_lsblk
1031
+ report_result if @run_already # Last but not least, report the result.
1032
+ end
1033
+
1034
+ # ========================================================================= #
1035
+ # === HardwareInformation.run
1036
+ # ========================================================================= #
1037
+ def self.run
1038
+ new
1039
+ end; self.instance_eval { alias report run } # === HardwareInformation.report
1040
+
1041
+ end
1042
+
1043
+ if __FILE__ == $PROGRAM_NAME
1044
+ _ = HardwareInformation.new(false)
1045
+ # _.disable_colours
1046
+ _.run
1047
+ _.report_result
1048
+ end # hardi