environment_information 1.4.124 → 1.5.5

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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +91 -15
  3. data/doc/README.gen +42 -14
  4. data/doc/todo/TODO_FOR_THE_ENVIRONMENT_INFORMATION_PROJECT.md +16 -12
  5. data/lib/environment_information/base/base.rb +483 -99
  6. data/lib/environment_information/colours/colours.rb +92 -66
  7. data/lib/environment_information/commandline/commandline.rb +137 -0
  8. data/lib/environment_information/constants/constants.rb +372 -11
  9. data/lib/environment_information/project/project.rb +1 -1
  10. data/lib/environment_information/query/constants.rb +46 -0
  11. data/lib/environment_information/query/help.rb +88 -0
  12. data/lib/environment_information/query/menu.rb +487 -0
  13. data/lib/environment_information/query/misc.rb +2006 -0
  14. data/lib/environment_information/query/query.rb +245 -0
  15. data/lib/environment_information/query/reset.rb +202 -0
  16. data/lib/environment_information/query/run.rb +70 -0
  17. data/lib/environment_information/requires/require_the_environment_information_project.rb +2 -7
  18. data/lib/environment_information/requires/require_the_toplevel_methods.rb +1 -3
  19. data/lib/environment_information/toplevel_methods/toplevel_methods.rb +2258 -0
  20. data/lib/environment_information/version/version.rb +2 -2
  21. data/lib/environment_information/www/sinatra_interface.rb +20 -17
  22. data/lib/environment_information/www/webobject_interface.cgi +6 -7
  23. data/lib/environment_information/yaml/colours.yml +3 -3
  24. data/lib/environment_information/yaml/query_to_use_for_all_components.yml +284 -0
  25. data/lib/environment_information/yaml/{array_tracked_programs.yml → track_these_components.yml} +77 -11
  26. metadata +18 -60
  27. data/lib/environment_information/class/class.rb +0 -2580
  28. data/lib/environment_information/class/colours.rb +0 -282
  29. data/lib/environment_information/colours/sfancy.rb +0 -19
  30. data/lib/environment_information/colours/simp.rb +0 -19
  31. data/lib/environment_information/constants/array_tracked_components.rb +0 -210
  32. data/lib/environment_information/constants/encoding.rb +0 -21
  33. data/lib/environment_information/constants/error_line.rb +0 -17
  34. data/lib/environment_information/constants/file_constants.rb +0 -102
  35. data/lib/environment_information/constants/misc.rb +0 -86
  36. data/lib/environment_information/constants/namespace.rb +0 -14
  37. data/lib/environment_information/constants/newline.rb +0 -16
  38. data/lib/environment_information/constants/regex.rb +0 -30
  39. data/lib/environment_information/constants/temp_directory.rb +0 -52
  40. data/lib/environment_information/misc_components/README.md +0 -3
  41. data/lib/environment_information/misc_components/cflags.rb +0 -36
  42. data/lib/environment_information/misc_components/cpuinfo.rb +0 -64
  43. data/lib/environment_information/misc_components/operating_system.rb +0 -54
  44. data/lib/environment_information/misc_components/operating_system_bit_type.rb +0 -42
  45. data/lib/environment_information/misc_components/ram.rb +0 -30
  46. data/lib/environment_information/misc_components/rubygems_installation_directory.rb +0 -54
  47. data/lib/environment_information/misc_components/screen_resolution.rb +0 -50
  48. data/lib/environment_information/queries/README.md +0 -2
  49. data/lib/environment_information/queries/complex_version.rb +0 -273
  50. data/lib/environment_information/queries/pkg_config.rb +0 -125
  51. data/lib/environment_information/queries/simple_version.rb +0 -272
  52. data/lib/environment_information/requires/require_the_individual_misc_components.rb +0 -30
  53. data/lib/environment_information/toplevel_methods/autogenerate_all_relevant_methods.rb +0 -153
  54. data/lib/environment_information/toplevel_methods/cd.rb +0 -16
  55. data/lib/environment_information/toplevel_methods/e.rb +0 -43
  56. data/lib/environment_information/toplevel_methods/hash.rb +0 -65
  57. data/lib/environment_information/toplevel_methods/internet_is_available.rb +0 -30
  58. data/lib/environment_information/toplevel_methods/is_on_roebe.rb +0 -16
  59. data/lib/environment_information/toplevel_methods/menu.rb +0 -90
  60. data/lib/environment_information/toplevel_methods/misc.rb +0 -324
  61. data/lib/environment_information/toplevel_methods/n_subcommands.rb +0 -31
  62. data/lib/environment_information/toplevel_methods/prefix_to_use.rb +0 -39
  63. data/lib/environment_information/toplevel_methods/register_this_component_is_missing.rb +0 -61
  64. data/lib/environment_information/toplevel_methods/remote_url_of_this_program.rb +0 -45
  65. data/lib/environment_information/toplevel_methods/replay_from_the_stored_file.rb +0 -84
  66. data/lib/environment_information/toplevel_methods/return_alias_to.rb +0 -30
  67. data/lib/environment_information/toplevel_methods/return_pkgconfig_based_programs.rb +0 -28
  68. data/lib/environment_information/toplevel_methods/return_remote_gtk2_version.rb +0 -54
  69. data/lib/environment_information/toplevel_methods/return_simple_version_based_programs.rb +0 -28
  70. data/lib/environment_information/toplevel_methods/return_version_of_this_program.rb +0 -182
  71. data/lib/environment_information/toplevel_methods/show_all_available_components.rb +0 -192
  72. data/lib/environment_information/toplevel_methods/write_what_into.rb +0 -24
  73. data/lib/environment_information/yaml/array_default_programs_on_linux.yml +0 -15
  74. data/lib/environment_information/yaml/array_lfs_core_programs.yml +0 -37
  75. data/lib/environment_information/yaml/array_science_cluster.yml +0 -12
  76. data/lib/environment_information/yaml/array_tracked_non_programs.yml +0 -13
  77. data/lib/environment_information/yaml/array_tracked_xorg_components.yml +0 -37
  78. data/lib/environment_information/yaml/query_to_use_for_the_individual_components.yml +0 -284
@@ -0,0 +1,2258 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ # require 'environment_information/toplevel_methods/toplevel_methods.rb'
6
+ # EnvironmentInformation.return_simple_version_based_programs
7
+ # EnvironmentInformation.return_version_of_this_program(:ccache)
8
+ # EnvironmentInformation.return_pkgconfig_based_programs
9
+ # EnvironmentInformation.return_version_of_mpc
10
+ # =========================================================================== #
11
+ module EnvironmentInformation
12
+
13
+ require 'yaml'
14
+ require 'environment_information/constants/constants.rb'
15
+
16
+ begin
17
+ require 'rbt/requires/swift_version.rb'
18
+ rescue LoadError; end
19
+
20
+ begin
21
+ require 'rbt/toplevel_methods/url.rb'
22
+ rescue LoadError; end
23
+
24
+ # ========================================================================= #
25
+ # === @hash_available_programs
26
+ #
27
+ # This hash stores the available programs.
28
+ #
29
+ # We need to use a Hash, rather than an Array, because we may save
30
+ # the result into a file, such as a yaml file. It is then more
31
+ # convenient to have the names of the program appear on the left
32
+ # side directoy, and the version on the right side.
33
+ #
34
+ # This Hash will hold the program name on the left side, and the
35
+ # program version on the right side. A nil value on the right
36
+ # side indicates that this program is NOT installed - which
37
+ # makes this the default value.
38
+ # ========================================================================= #
39
+ @hash_available_programs = {}
40
+
41
+ # ========================================================================= #
42
+ # === EnvironmentInformation.hash?
43
+ #
44
+ # This method will return the Hash of all available programs.
45
+ # ========================================================================= #
46
+ def self.hash?
47
+ @hash_available_programs
48
+ end; self.instance_eval { alias hash hash? } # === EnvironmentInformation.hash
49
+ self.instance_eval { alias dataset? hash? } # === EnvironmentInformation.dataset?
50
+ self.instance_eval { alias hash_available_programs? hash? } # === EnvironmentInformation.hash_available_programs?
51
+
52
+ # ========================================================================== #
53
+ # === EnvironmentInformation.e
54
+ # ========================================================================== #
55
+ def self.e(
56
+ i = '',
57
+ hash = {}
58
+ )
59
+ if hash and
60
+ hash.has_key?(:display_everything_in_short_format) and
61
+ hash[:display_everything_in_short_format]
62
+ # ===================================================================== #
63
+ # Display the results in a single line in this case, separated
64
+ # via ',' tokens.
65
+ # ===================================================================== #
66
+ print "#{i}, "
67
+ else # This variant here is the default.
68
+ puts i
69
+ end
70
+ end
71
+
72
+ # ========================================================================= #
73
+ # === EnvironmentInformation.add_to_hash
74
+ #
75
+ # a refers to left; b refers to right.
76
+ # ========================================================================= #
77
+ def self.add_to_hash(a, b)
78
+ b.strip! if b.is_a?(String) and !b.frozen?
79
+ if b.nil? # Here we did not provide a value for b.
80
+ ::EnvironmentInformation.register_this_component_is_missing(a)
81
+ end
82
+ @hash_available_programs[a] = b
83
+ end
84
+
85
+ # ========================================================================= #
86
+ # === EnvironmentInformation.clear_hash
87
+ #
88
+ # This method can be used to clear the main (toplevel) Hash.
89
+ # ========================================================================= #
90
+ def self.clear_hash
91
+ @hash_available_programs.clear
92
+ end; self.instance_eval { alias clear_toplevel_hash clear_hash } # === EnvironmentInformation.clear_toplevel_hash
93
+ self.instance_eval { alias clear_main_hash clear_hash } # === EnvironmentInformation.clear_main_hash
94
+
95
+ # ========================================================================== #
96
+ # === @debug
97
+ #
98
+ # This variable can be used to control whether we debug the project
99
+ # or not. It should be false by default (and upon re-destribution of
100
+ # the project to other users).
101
+ # ========================================================================== #
102
+ @debug = false
103
+
104
+ # ========================================================================== #
105
+ # === EnvironmentInformation.return_the_most_important_info
106
+ #
107
+ # This method will just return a String that can be used right away
108
+ # in, for example, a sinatra application or a RoR application.
109
+ # ========================================================================== #
110
+ def self.return_the_most_important_info
111
+ "Operating system: "+
112
+ "#{::EnvironmentInformation.operating_system}<br>"+
113
+ "Operating system bit type: "+
114
+ "#{::EnvironmentInformation.operating_system_bit_type}<br>"+
115
+ "CPU model: "+
116
+ "#{::EnvironmentInformation.cpu_model}<br>"
117
+ end
118
+
119
+ # ========================================================================== #
120
+ # === EnvironmentInformation.n_subcommands?
121
+ #
122
+ # Return how many subcommands are available/registered. These are
123
+ # the tracked programs; and the xorg-components.
124
+ #
125
+ # The non-programs will not be gathered by this method, on purpose; they
126
+ # are not standalone programs after all.
127
+ #
128
+ # As of August 2020, 167 programs were tracked by this gem.
129
+ #
130
+ # As of March 2024, 256 components were tracked by this gem, so about
131
+ # 250 programs, give or take.
132
+ # ========================================================================== #
133
+ def self.n_subcommands?
134
+ ARRAY_TRACKED_PROGRAMS.size
135
+ end
136
+
137
+ # ========================================================================== #
138
+ # === @prefix_to_use
139
+ #
140
+ # This variable can be used to designate another base directory to
141
+ # be used, such as at /home/Programs/ or opt. This allows us to scan
142
+ # through an AppDir and output the programs found there.
143
+ #
144
+ # By default it must be an empty String, as many other files check
145
+ # on the content of this variable - so only change it if you really
146
+ # need to use another prefix to use.
147
+ #
148
+ # The functionality was specifically added to support versioned
149
+ # AppDirs on a given computer system.
150
+ # ========================================================================== #
151
+ @prefix_to_use = ''.dup
152
+
153
+ # ========================================================================== #
154
+ # === EnvironmentInformation.set_prefix_to_use
155
+ # ========================================================================== #
156
+ def self.set_prefix_to_use(i)
157
+ @prefix_to_use = i.to_s.dup
158
+ end; self.instance_eval { alias set_prefix set_prefix_to_use } # === EnvironmentInformation.set_prefix
159
+
160
+ # ========================================================================== #
161
+ # === EnvironmentInformation.prefix?
162
+ # ========================================================================== #
163
+ def self.prefix?
164
+ @prefix_to_use
165
+ end
166
+
167
+ # ========================================================================== #
168
+ # === EnvironmentInformation.return_version_of_doubleconversion
169
+ # ========================================================================== #
170
+ def self.return_version_of_doubleconversion(
171
+ target_file = '/usr/lib/cmake/double-conversion/double-conversionConfigVersion.cmake'
172
+ )
173
+ if File.exist? target_file
174
+ dataset = File.read(target_file)
175
+ result = dataset.scan(
176
+ /PACKAGE_VERSION "(.+)"/
177
+ ).flatten.first.to_s
178
+ return result
179
+ else
180
+ return nil
181
+ end
182
+ end
183
+
184
+ # ========================================================================== #
185
+ # === EnvironmentInformation.return_version_of_boost
186
+ #
187
+ # This method will either return a String (the version of boost),
188
+ # or nil if boost was not found.
189
+ # ========================================================================== #
190
+ def self.return_version_of_boost
191
+ target_file = '/usr/include/boost/version.hpp'
192
+ if File.exist?('/System/Index/include/boost/version.hpp') and
193
+ !File.exist?(target_file) # Custom fix.
194
+ target_file = '/System/Index/include/boost/version.hpp'
195
+ end
196
+ if File.exist? target_file
197
+ dataset = File.readlines(target_file)
198
+ version = dataset.select {|line|
199
+ line.include? '#define BOOST_LIB_VERSION'
200
+ }.first.sub(/#define BOOST_LIB_VERSION/,'').
201
+ strip.delete('"').tr('_','.')
202
+ if version.count('.') < 2
203
+ version << '.0'
204
+ end
205
+ else
206
+ version = nil
207
+ end
208
+ return version
209
+ end
210
+
211
+ # ========================================================================== #
212
+ # === EnvironmentInformation.return_version_of_xvid
213
+ # ========================================================================== #
214
+ def self.return_version_of_xvid(
215
+ target_file = '/usr/include/xvid.h'
216
+ )
217
+ if File.exist?('/System/Index/include/'+File.basename(target_file)) and
218
+ !File.exist?(target_file) # Custom fix.
219
+ target_file = '/System/Index/include/'+File.basename(target_file)
220
+ end
221
+ if File.exist? target_file
222
+ dataset = File.readlines(target_file)
223
+ version = dataset.select {|line|
224
+ line.include? ' XVID_MAKE_VERSION(' # #define XVID_VERSION XVID_MAKE_VERSION(1,3,7)
225
+ }
226
+ if version.is_a? Array
227
+ version = version.flatten.first.to_s
228
+ end
229
+ version = version.scan( # See: https://rubular.com/r/4anuroBmb40yzh
230
+ /XVID_MAKE_VERSION\((\d{0,1},\d{0,1},\d{0,1})/
231
+ )
232
+ if version.is_a? Array
233
+ version = version.flatten.first.to_s
234
+ end
235
+ version.tr!(',','.')
236
+ else
237
+ version = nil
238
+ end
239
+ return version
240
+ end
241
+
242
+ # ========================================================================== #
243
+ # === EnvironmentInformation.is_this_program_included?
244
+ #
245
+ # This will include the two Arrays ARRAY_TRACKED_PROGRAMS and
246
+ # ARRAY_XORG_COMPONENTS, but it will NOT include ARRAY_TRACKED_NON_PROGRAMS.
247
+ # ========================================================================== #
248
+ def self.is_this_program_included?(i)
249
+ (
250
+ ARRAY_TRACKED_PROGRAMS
251
+ ).flatten.include? i.to_sym # Need a symbol.
252
+ end; self.instance_eval { alias is_this_a_registered_program? is_this_program_included? } # === ::EnvironmentInformation.is_this_a_registered_program?
253
+
254
+ # ========================================================================== #
255
+ # === EnvironmentInformation.cd (cd tag)
256
+ # ========================================================================== #
257
+ def self.cd(i)
258
+ Dir.chdir(i) if File.directory? i
259
+ end
260
+
261
+ # ========================================================================== #
262
+ # === EnvironmentInformation.is_on_roebe?
263
+ # ========================================================================== #
264
+ def self.is_on_roebe?
265
+ ENV['IS_ROEBE'].to_i == 1
266
+ end
267
+
268
+ # ========================================================================= #
269
+ # === EnvironmentInformation.show_all_available_components
270
+ #
271
+ # This method will quickly and easily show all available (registered)
272
+ # components. If you need more fine-tuning when you wish to display
273
+ # the main dataset at hand, then you should use other methods that
274
+ # are also a bit more complex. This method here is really just a
275
+ # fast version-display overview.
276
+ #
277
+ # The second argument to this method contains the programs that we
278
+ # wish to display through this method.
279
+ # ========================================================================= #
280
+ def self.show_all_available_components(
281
+ n_ljust = 18,
282
+ show_these_components = tracked_programs?,
283
+ use_colours = use_colours?
284
+ )
285
+ clear_main_hash
286
+ if show_these_components.is_a? Array
287
+ show_these_components.flatten!
288
+ end
289
+ # ======================================================================= #
290
+ # The next variable determines whether we will also compare the
291
+ # program versions.
292
+ # ======================================================================= #
293
+ compare_program_versions = false
294
+ default_nljust_value = 30 # ← Detemine default padding.
295
+ if n_ljust.is_a?(Array) and n_ljust.empty?
296
+ n_ljust = default_nljust_value # Use the default value in this case.
297
+ end
298
+ # ======================================================================= #
299
+ # First we will treat n_ljust as a commandline-flag if it is a String
300
+ # and additionally begins with "--".
301
+ # ======================================================================= #
302
+ if n_ljust.is_a?(Array) and n_ljust.first.start_with?('--')
303
+ _ = n_ljust.first
304
+ case _
305
+ # ===================================================================== #
306
+ # === --help
307
+ #
308
+ # Invocation example:
309
+ #
310
+ # showcomponents --help
311
+ #
312
+ # ===================================================================== #
313
+ when /^-?-?help$/i
314
+ e 'The following options are available for bin/fast_envi (fenvi):'
315
+ e
316
+ e ' --xorg # show only the xorg-components'
317
+ e ' --compare-to-program-versions # also compare the program versions'
318
+ e
319
+ exit
320
+ # ===================================================================== #
321
+ # === --compare-to-program-versions
322
+ #
323
+ # To invoke this, try:
324
+ #
325
+ # show_components --compare
326
+ # envi --compare-version
327
+ #
328
+ # ===================================================================== #
329
+ when *ARRAY_COMPARE_PROGRAM_VERSIONS
330
+ compare_program_versions = true
331
+ n_ljust = default_nljust_value
332
+ # ===================================================================== #
333
+ # === --xorg
334
+ # ===================================================================== #
335
+ when /^-?-?xorg$/i
336
+ show_these_components = ::EnvironmentInformation.xorg_components?
337
+ n_ljust = default_nljust_value
338
+ end
339
+ end
340
+ e
341
+ uniq = show_these_components.uniq
342
+ uniq.sort.each {|this_program|
343
+ use_this_name_for_send = "return_version_of_#{this_program}"
344
+ # ===================================================================== #
345
+ # Next, add the name of the program at hand, onto the left hand side:
346
+ # ===================================================================== #
347
+ result = this_program.to_s.ljust(n_ljust)
348
+ if use_colours
349
+ result = ::EnvironmentInformation.colourize_and_pad_the_left_side(result)
350
+ end
351
+ # ===================================================================== #
352
+ # Some components may not be installed on the user's computer system,
353
+ # which we have to keep in mind in the following code. This is
354
+ # why we will first apply the .send(), before checking whether
355
+ # the program at hand is actually missing or not.
356
+ # ===================================================================== #
357
+ result_of_send = send(use_this_name_for_send)
358
+ if result_of_send
359
+ result_of_send = result_of_send.dup if result_of_send.frozen?
360
+ result_of_send.strip!
361
+ end
362
+ @hash_available_programs[this_program.to_sym] = result_of_send.to_s
363
+ right_component = ''.dup
364
+ if @array_this_component_is_missing.include?(this_program.to_sym)
365
+ right_component << "not installed (or otherwise not found)".ljust(12)
366
+ else
367
+ right_component << result_of_send.ljust(12) if result_of_send
368
+ end
369
+ if use_colours
370
+ # =================================================================== #
371
+ # We will distinguish between components that have been found and
372
+ # components that have not been found.
373
+ # =================================================================== #
374
+ if right_component.include?('not installed')
375
+ right_component = ::Colours.send(:mediumslateblue, right_component)
376
+ else
377
+ right_component = ::Colours.send(colour_for_the_right_side, right_component)
378
+ end
379
+ end
380
+ result = result.dup if result.frozen?
381
+ result << right_component
382
+ if compare_program_versions
383
+ if is_this_program_included?(this_program)
384
+ registered_local_version = RBT.swift_return_version_of_this_program(this_program.to_sym).to_s.dup
385
+ if registered_local_version.include? 'v'
386
+ # =============================================================== #
387
+ # Modify entries such as 'v12.15.0' into '12.15.0'.
388
+ # =============================================================== #
389
+ registered_local_version.delete!('v')
390
+ end
391
+ case this_program.to_s
392
+ when 'gtk2'
393
+ registered_local_version = query_pkgconfig_version_for(:gtk2)
394
+ else
395
+ if result_of_send.nil?
396
+ # ^^^ This is missing, then, so it will be ignored.
397
+ elsif registered_local_version <= result_of_send
398
+ # This is ok.
399
+ else
400
+ result <<
401
+ royalblue(
402
+ "\n "\
403
+ "^^^ This could be updated; the version in "\
404
+ "RBT is: #{mediumpurple(registered_local_version)}"
405
+ )
406
+ end
407
+ end
408
+ end
409
+ end
410
+ # ===================================================================== #
411
+ # Finally display our findings to the end user.
412
+ # ===================================================================== #
413
+ e result
414
+ }
415
+ e
416
+ if is_on_roebe? # And store it on my home system too.
417
+ ::EnvironmentInformation.store_relevant_files
418
+ end
419
+ end
420
+
421
+ # ========================================================================= #
422
+ # === EnvironmentInformation.replay_from_the_stored_file
423
+ #
424
+ # To invoke this method from the commandline, try:
425
+ #
426
+ # envi --replay
427
+ #
428
+ # ========================================================================= #
429
+ def self.replay_from_the_stored_file(
430
+ _ = return_path_to_the_all_programs_file
431
+ )
432
+ if File.exist? _
433
+ e "Loading from the file #{_}."
434
+ @hash_available_programs = YAML.load_file(_)
435
+ @hash_available_programs.each_pair {|key, value|
436
+ e "#{key}:"+value.to_s
437
+ }
438
+ else
439
+ e "No file exists at #{_}."
440
+ end
441
+ end
442
+
443
+ # ========================================================================== #
444
+ # === EnvironmentInformation.ee
445
+ #
446
+ # This is simply a wrapper over print, as well as adding a ', ' to that.
447
+ # ========================================================================== #
448
+ def self.ee(
449
+ i = ''
450
+ )
451
+ print "#{i}, "
452
+ end
453
+
454
+ # ========================================================================== #
455
+ # === EnvironmentInformation.internet_is_available?
456
+ # ========================================================================== #
457
+ def self.internet_is_available?
458
+ require 'resolv'
459
+ dns_resolver = Resolv::DNS.new
460
+ begin
461
+ # ====================================================================== #
462
+ # The first domain name ever. Will probably not be removed.
463
+ # ====================================================================== #
464
+ dns_resolver.getaddress('symbolics.com')
465
+ return true
466
+ rescue Resolv::ResolvError => _error
467
+ return false
468
+ end
469
+ end
470
+
471
+ # ========================================================================== #
472
+ # === EnvironmentInformation.return_alias_to
473
+ #
474
+ # This method will return some abbreviations to programs.
475
+ # ========================================================================== #
476
+ def self.return_alias_to(i)
477
+ if i.is_a? Array
478
+ i = i.first
479
+ end
480
+ case i.to_sym
481
+ # ======================================================================== #
482
+ # === :find
483
+ # ======================================================================== #
484
+ when :find
485
+ i = :findutils
486
+ # ======================================================================== #
487
+ # === :diff
488
+ # ======================================================================== #
489
+ when :diff
490
+ i = :diffutils
491
+ # ======================================================================== #
492
+ # === :yacc
493
+ # ======================================================================== #
494
+ when :yacc
495
+ i = :bison
496
+ end
497
+ return i # Always return something.
498
+ end
499
+
500
+ # ========================================================================== #
501
+ # === Environment.verbose_truth
502
+ # ========================================================================== #
503
+ def self.verbose_truth(i)
504
+ case i
505
+ when /true/
506
+ 'Yes.'
507
+ when /false/
508
+ 'No.'
509
+ end
510
+ end
511
+
512
+ # ========================================================================== #
513
+ # === EnvironmentInformation.load_file_query_to_use_for_the_individual_components
514
+ # ========================================================================== #
515
+ def self.load_file_query_to_use_for_the_individual_components(
516
+ i = ::EnvironmentInformation.project_base_directory?+
517
+ 'yaml/query_to_use_for_all_components.yml' # FILE_QUERY_TO_USE_FOR_THE_INDIVIDUAL_COMPONENTS
518
+ )
519
+ if File.exist? i
520
+ return YAML.load_file(i)
521
+ else
522
+ return {}
523
+ end
524
+ end; self.instance_eval { alias all_the_queries load_file_query_to_use_for_the_individual_components } # === EnvironmentInformation.all_the_queries
525
+ self.instance_eval { alias query_to_use_for_all_components load_file_query_to_use_for_the_individual_components } # === EnvironmentInformation.query_to_use_for_all_components
526
+ self.instance_eval { alias query_to_use_for_all_components? load_file_query_to_use_for_the_individual_components } # === EnvironmentInformation.query_to_use_for_all_components?
527
+
528
+ # ========================================================================== #
529
+ # === EnvironmentInformation.return_remote_gtk2_version
530
+ #
531
+ # This method can be used to obtain the latest gtk2-version, from a
532
+ # remote URL.
533
+ #
534
+ # The reason why this was necessary is because the RBT project may not
535
+ # always keep the latest gtk2 version, since gtk3 (and so forth) is more
536
+ # recent. Since we may still have to find out which gtk2 version is the
537
+ # most recent, we need a method to do so - which is precisely what this
538
+ # method here is doing.
539
+ # ========================================================================== #
540
+ def self.return_remote_gtk2_version
541
+ # ======================================================================= #
542
+ # We will use a hardcoded URL pointing towards gtk2:
543
+ # ======================================================================= #
544
+ remote_url = 'https://ftp.gnome.org/pub/GNOME/sources/gtk+/2.24/?C=M;O=D'
545
+ require 'open-uri'
546
+ newest_version = ''
547
+ # ======================================================================= #
548
+ # We will next try to obtain the remote dataset, but this would
549
+ # fail if we have no www-connection, so we must rescue this step.
550
+ # ======================================================================= #
551
+ if internet_is_available?
552
+ begin
553
+ dataset = URI.open(remote_url).read
554
+ use_this_regex =
555
+ /<a href="gtk\+\-(\d.\d\d.\d\d).tar.xz"><img src=/
556
+ scanned = dataset.scan(use_this_regex).flatten
557
+ newest_version = scanned.first
558
+ rescue SocketError => error
559
+ puts "It seems as if we have no working internet "\
560
+ "connection (#{sfancy(error.class)})"
561
+ end
562
+ end
563
+ return newest_version.strip # ← And return it here.
564
+ end
565
+
566
+ # ========================================================================== #
567
+ # === EnvironmentInformation.is_this_component_included?
568
+ #
569
+ # This is a more extensive check than .is_this_program_included?()
570
+ # ========================================================================== #
571
+ def self.is_this_component_included?(i)
572
+ array = tracked_components?
573
+ array.flatten.include? i.to_sym # Need a Symbol as input.
574
+ end
575
+
576
+ # ========================================================================== #
577
+ # === EnvironmentInformation.lfs_core_programs?
578
+ # ========================================================================== #
579
+ def self.lfs_core_programs?
580
+ ARRAY_LFS_CORE_PROGRAMS
581
+ end
582
+
583
+ # ========================================================================== #
584
+ # === EnvironmentInformation.return_version_of_busybox (busybox tag)
585
+ # ========================================================================== #
586
+ def self.return_version_of_busybox(
587
+ i = "busybox #{ERROR_LINE}"
588
+ )
589
+ result = ::EnvironmentInformation.return_very_silent_system_output_from(i)
590
+ if result and result.is_a?(String) and result.include?("\n")
591
+ first_line = result.split("\n").first
592
+ if first_line.include? ' v'
593
+ # "BusyBox v1.32.0 (2020-11-08 04:41:56 Etc) multi-call binary.\n"
594
+ use_this_regex = /v(\d{0,1}.\d{0,2}.\d{0,1})/ # See: https://rubular.com/r/MpnFXlalLCXXGI
595
+ result = first_line.scan(use_this_regex).flatten.first.to_s
596
+ return result
597
+ end
598
+ end
599
+ return nil
600
+ end
601
+
602
+ # ========================================================================== #
603
+ # === EnvironmentInformation.return_version_of_xrandr
604
+ # ========================================================================== #
605
+ def self.return_version_of_xrandr(
606
+ i = 'xrandr --version'
607
+ )
608
+ result = ::EnvironmentInformation.return_very_silent_system_output_from(i)
609
+ if result
610
+ version = result.strip.split("\n")
611
+ if version.is_a?(Array)
612
+ version = version.first.split(' ').last.strip # Assume: "xrandr program version 1.5.1"
613
+ # or: result = splitted.first.sub(/xrandr program version/,'')
614
+ return version.strip
615
+ end
616
+ end
617
+ return nil
618
+ end
619
+
620
+ # ========================================================================== #
621
+ # === EnvironmentInformation.cflags? (cflags tag)
622
+ #
623
+ # The following is equivalent to the value stored in the variable
624
+ # $CFLAGS, which on unix-like systems may be obtained by issuing
625
+ # the following command:
626
+ #
627
+ # echo $CFLAGS
628
+ #
629
+ # The output may be like this:
630
+ #
631
+ # -O2 -fPIC -fno-strict-overflow -Wno-error
632
+ #
633
+ # ========================================================================== #
634
+ def self.cflags?
635
+ _ = ENV['CFLAGS'].to_s.strip
636
+ _ = '<none>' if _.empty? # Display special status if it is empty.
637
+ return _
638
+ end; self.instance_eval { alias return_version_of_cflags cflags? } # === EnvironmentInformation.return_version_of_cflags
639
+ self.instance_eval { alias cflags cflags? } # === EnvironmentInformation.cflags
640
+ self.instance_eval { alias cflags_in_use? cflags? } # === EnvironmentInformation.cflags_in_use?
641
+
642
+ # ========================================================================== #
643
+ # === EnvironmentInformation.rubygems_installation_directory
644
+ #
645
+ # This method will return the path to the rubygems installation
646
+ # directory, if possible (if it exists).
647
+ #
648
+ # As this ought to be a directory, we will ensure that a trailing '/'
649
+ # token is returned.
650
+ #
651
+ # This method may return a String such as "/root/.gem/".
652
+ # ========================================================================== #
653
+ def self.rubygems_installation_directory(
654
+ prefix_to_use = @prefix_to_use
655
+ )
656
+ result = silent_sys_command("#{prefix_to_use}gem env")
657
+ unless result.include? 'not found'
658
+ # ===================================================================== #
659
+ # Apply a regex next.
660
+ # ===================================================================== #
661
+ path_to_the_rubygem_directory = result.to_s.scan(
662
+ /INSTALLATION DIRECTORY: (.+)/ # Obtain the proper match here.
663
+ ).flatten.first.to_s
664
+ if File.directory? path_to_the_rubygem_directory
665
+ path_to_the_rubygem_directory << '/' # Append the trailing '/' here.
666
+ end unless path_to_the_rubygem_directory.end_with? '/'
667
+ result = path_to_the_rubygem_directory
668
+ else
669
+ result = nil
670
+ end
671
+ return result
672
+ end; self.instance_eval { alias add_rubygems_installation_directory_information rubygems_installation_directory } # === EnvironmentInformation.add_rubygems_installation_directory_information
673
+ self.instance_eval { alias add_rubygem_directory_information rubygems_installation_directory } # === EnvironmentInformation.add_rubygem_directory_information
674
+ self.instance_eval { alias append_rubygem_installation_directory rubygems_installation_directory } # === EnvironmentInformation.append_rubygem_installation_directory
675
+ self.instance_eval { alias return_version_of_rubygems_installation_directory rubygems_installation_directory } # === EnvironmentInformation.return_version_of_rubygems_installation_directory
676
+ self.instance_eval { alias rubygems_installation_directory? rubygems_installation_directory } # === EnvironmentInformation.rubygems_installation_directory?
677
+
678
+ # ========================================================================== #
679
+ # === EnvironmentInformation.screen_resolution (screen tag)
680
+ #
681
+ # This method will typically make use of xdpyinfo first, as it also
682
+ # works in a .cgi environment. For non-cgi environments, on linux,
683
+ # we could use xrandr, which is a bit more elegant.
684
+ #
685
+ # On success, the method here will return a String such as "1920x1080".
686
+ # ========================================================================== #
687
+ def self.screen_resolution
688
+ result = '(unknown)' # This is the default return-value, then.
689
+ # ======================================================================= #
690
+ # === Check for linux as host OS first
691
+ # ======================================================================= #
692
+ if RUBY_PLATFORM.downcase.include? 'linux'
693
+ # ================================================================= #
694
+ # We have to be careful as xdpyinfo may not be installed on the
695
+ # given computer system.
696
+ # ================================================================= #
697
+ # resolution = `xdpyinfo #{ERROR_LINE}`.scan(/dimensions:.+$/).first # The error here may be: "xdpyinfo: unable to open display"
698
+ resolution = silent_sys_command('xdpyinfo').scan(/dimensions:.+$/).first # The error here may be: "xdpyinfo: unable to open display"
699
+ if resolution and resolution.include? ':'
700
+ result = resolution.split(':').last.strip.split('pixels').first.strip # Or split on: /(\d{1,5}x\d{1,4})/
701
+ end
702
+ # ======================================================================= #
703
+ # === Else simply assume the computer to run windows here
704
+ # ======================================================================= #
705
+ else
706
+ result = `wmic desktopmonitor get screenheight,screenwidth #{ERROR_LINE}`
707
+ end
708
+ return result
709
+ end; self.instance_eval { alias screen_resolution? screen_resolution } # === EnvironmentInformation.screen_resolution?
710
+ self.instance_eval { alias return_version_of_screen_resolution screen_resolution } # === EnvironmentInformation.return_version_of_screen_resolution
711
+
712
+ # ========================================================================== #
713
+ # === EnvironmentInformation.ram? (ram tag)
714
+ #
715
+ # This method will determine how much RAM the given computer host has.
716
+ #
717
+ # The result will be given in n MB.
718
+ #
719
+ # Alternatively we could use /proc/meminfo and look for 'MemTotal:'.
720
+ # ========================================================================== #
721
+ def self.ram?
722
+ result_in_n_mb = silent_sys_command('free -m').split("\n")[1]
723
+ if result_in_n_mb and result_in_n_mb.include?(' ')
724
+ result_in_n_mb = result_in_n_mb.split(' ')[1]
725
+ end
726
+ return result_in_n_mb
727
+ end; self.instance_eval { alias return_version_of_ram ram? } # === EnvironmentInformation.return_version_of_ram
728
+ self.instance_eval { alias ram ram? } # === EnvironmentInformation.ram
729
+
730
+ # ========================================================================== #
731
+ # === EnvironmentInformation.operating_system (os tag)
732
+ #
733
+ # This method is also known as "bit type".
734
+ #
735
+ # The return value of this method may be a String such as this one here:
736
+ #
737
+ # "GNU/Linux"
738
+ #
739
+ # This is then further modified a bit to drop the "GNU/" part
740
+ # specifically.
741
+ #
742
+ # An alternative to "uname -mo" would be "uname -a".
743
+ # ========================================================================== #
744
+ def self.operating_system(
745
+ i = 'uname -mo'
746
+ )
747
+ result = silent_sys_command(i).chomp
748
+ if result.start_with? 'GNU'
749
+ # ====================================================================== #
750
+ # The next part removes 'GNU/' specifically. It is a simpler name
751
+ # than "GNU Linux" and variants, just as "BSD" is simpler than
752
+ # e. g. "FreeBSD". You can reason that it may be "less accurate",
753
+ # but it makes the notification-part of this gem simpler.
754
+ # ====================================================================== #
755
+ result.sub!(/^GNU\//,'') # Experimental as of Sep 2019.
756
+ end
757
+ if result.include? ' '
758
+ result = result.split(' ').last
759
+ end
760
+ return result
761
+ end; self.instance_eval { alias operating_system? operating_system } # === EnvironmentInformation.operating_system?
762
+ self.instance_eval { alias operating_system_information? operating_system } # === EnvironmentInformation.operating_system_information
763
+ self.instance_eval { alias add_operating_system_information operating_system } # === EnvironmentInformation.add_operating_system_information
764
+ self.instance_eval { alias append_operating_system_in_use operating_system } # === EnvironmentInformation.append_operating_system_in_use
765
+ self.instance_eval { alias add_os_information operating_system } # === EnvironmentInformation.add_os_information
766
+ self.instance_eval { alias operating_system_in_use? operating_system } # === EnvironmentInformation.operating_system_in_use?
767
+ self.instance_eval { alias return_version_of_operating_system operating_system } # === EnvironmentInformation.return_version_of_operating_system
768
+ self.instance_eval { alias return_version_of_operating_system_in_use operating_system } # === EnvironmentInformation.return_version_of_operating_system_in_use
769
+
770
+ # ========================================================================== #
771
+ # === EnvironmentInformation.operating_system_bit_type_information (bit tag, bit type tag)
772
+ #
773
+ # This method will return the bit type in use, as a String, such as "x86_64"
774
+ # or "x86_64 (64 bit)" specifically. The reason why this method appends
775
+ # ' (64 bit)' is mostly so that the user can quickly see whether a computer
776
+ # is on 32 bit or on 64 bit.
777
+ # ========================================================================== #
778
+ def self.operating_system_bit_type_information
779
+ result = silent_sys_command('uname -m')
780
+ result.chomp!
781
+ result = result.split(' ')[-1] if result.include?(' ')
782
+ result = result.dup if result.frozen?
783
+ case result
784
+ when 'x86_64'
785
+ result << ' (64 bit)'
786
+ end
787
+ return result
788
+ end; self.instance_eval { alias bit_type? operating_system_bit_type_information } # === EnvironmentInformation.bit_type?
789
+ self.instance_eval { alias return_version_of_operating_system_bit_type operating_system_bit_type_information } # === EnvironmentInformation.return_version_of_operating_system_bit_type
790
+ self.instance_eval { alias add_bit_type_information operating_system_bit_type_information } # === EnvironmentInformation.add_bit_type_information
791
+ self.instance_eval { alias add_operating_system_bit_type operating_system_bit_type_information } # === EnvironmentInformation.add_operating_system_bit_type
792
+ self.instance_eval { alias operating_system_bit_type? operating_system_bit_type_information } # === EnvironmentInformation.operating_system_bit_type?
793
+ self.instance_eval { alias operating_system_bit_type operating_system_bit_type_information } # === EnvironmentInformation.operating_system_bit_type
794
+
795
+ # ========================================================================== #
796
+ # === EnvironmentInformation.return_version_of_mpc
797
+ #
798
+ # This method will read the version-string from a .h header file.
799
+ # ========================================================================== #
800
+ def self.return_version_of_mpc
801
+ target_file = '/usr/include/mpc.h'
802
+ if File.exist? target_file
803
+ dataset = File.read(target_file)
804
+ use_this_regex = /MPC_VERSION_STRING "([0-9\.]+)"$/
805
+ dataset = dataset.scan(use_this_regex).flatten
806
+ version = dataset.first
807
+ return version
808
+ else
809
+ return THE_PROGRAM_WAS_NOT_FOUND
810
+ end
811
+ end
812
+
813
+ # ========================================================================== #
814
+ # === EnvironmentInformation.return_remote_url_of_this_program
815
+ #
816
+ # This method will try to return the remote URL of the given program.
817
+ #
818
+ # Note that this functionality depends on the RBT project, which
819
+ # explains the rescued required statement in the method. While in
820
+ # theory we could create a stand-alone solution, I don't want to
821
+ # duplicate code I already wrote for another project, so users
822
+ # are encouraged to install the rbt gem - it's what I use on my
823
+ # home system as well.
824
+ # ========================================================================== #
825
+ def self.return_remote_url_of_this_program(i = ARGV)
826
+ if i.is_a? Array
827
+ i = i.first
828
+ end
829
+ begin
830
+ require 'rbt/cookbooks/url/url.rb'
831
+ i = RBT.return_url1_of_this_program(i)
832
+ rescue LoadError; end
833
+ i
834
+ end
835
+
836
+ # ========================================================================== #
837
+ # === EnvironmentInformation.show_remote_url_of_this_program
838
+ #
839
+ # This method will try to show the remote URL of the given program.
840
+ # ========================================================================== #
841
+ def self.show_remote_url_of_this_program(i = ARGV)
842
+ puts return_remote_url_of_this_program(i)
843
+ end
844
+
845
+ # ========================================================================== #
846
+ # === EnvironmentInformation.cpuinfo? (cpuinfo tag)
847
+ #
848
+ # This method currently relies on /proc/cpuinfo, thus favouring
849
+ # Linux-based systems.
850
+ #
851
+ # The output will be similar to this:
852
+ #
853
+ # AMD A8-7600 Radeon R7, 10 Compute Cores 4C+6G, 4 cores
854
+ #
855
+ # It will become the display part of "CPU Model", so this method is
856
+ # also known as the "cpu model".
857
+ # ========================================================================== #
858
+ def self.cpuinfo?
859
+ result = '/proc/cpuinfo'
860
+ if File.exist? result
861
+ readlines = File.readlines(result)
862
+ _ = readlines.grep(/model name/).first.chomp
863
+ splitted = _.split(':')
864
+ _ = splitted[1].strip # => "model name\t: AMD Sempron(tm) 145 Processor"
865
+ # ====================================================================== #
866
+ # Next, add the amount of cores. We use "nproc" for this but "lscpu"
867
+ # also contains this information. The following regex could be used
868
+ # for lscpu:
869
+ #
870
+ # Core\(s\) per socket: (.+)
871
+ #
872
+ # Ok, we use lscpu for now.
873
+ # ====================================================================== #
874
+ n_cores = silent_sys_command('nproc --all').to_s.strip
875
+ case n_cores
876
+ when '1'
877
+ n_cores << ' core' # Singular.
878
+ else
879
+ n_cores << ' cores' # Plural then.
880
+ end
881
+ _ << ", #{n_cores}" unless n_cores.empty?
882
+ result = _
883
+ else
884
+ result = nil
885
+ end
886
+ result
887
+ end; self.instance_eval { alias append_operating_system_cpuinfo cpuinfo? } # === EnvironmentInformation.append_operating_system_cpuinfo
888
+ self.instance_eval { alias cpu_model cpuinfo? } # === EnvironmentInformation.cpu_model
889
+ self.instance_eval { alias cpu_model? cpuinfo? } # === EnvironmentInformation.cpu_model?
890
+ self.instance_eval { alias return_version_of_cpuinfo cpuinfo? } # === EnvironmentInformation.return_version_of_cpuinfo
891
+ self.instance_eval { alias cpuinfo cpuinfo? } # === EnvironmentInformation.cpuinfo
892
+
893
+ # ========================================================================== #
894
+ # === EnvironmentInformation.write_what_into
895
+ # ========================================================================== #
896
+ def self.write_what_into(
897
+ what,
898
+ into
899
+ )
900
+ what = what.join("\n") if what.is_a? Array
901
+ File.open(into, 'w+') {|entry| entry.write(what) }
902
+ end
903
+
904
+ # ========================================================================== #
905
+ # === EnvironmentInformation.query_pkgconfig_version_for
906
+ #
907
+ # This toplevel-method can be used to query infromation stored in
908
+ # .pc files, done via the pkg-config utility.
909
+ #
910
+ # The input-argument to this method should be the name of the
911
+ # program at hand; and that program should be registered in the
912
+ # corresponding.yml file. The query will then use "pkg-config",
913
+ # which in turn queries the local .pc file for the version. So
914
+ # the local .pc file must be available, as otherwise this
915
+ # method will not find the necessary information.
916
+ # ========================================================================== #
917
+ def self.query_pkgconfig_version_for(
918
+ i = :gtk2
919
+ )
920
+ result = silent_sys_command("pkg-config --modversion #{i}")
921
+ if result.include? 'was not found in the pkg-config search pa'
922
+ result = NOT_FOUND
923
+ end
924
+ return result
925
+ end
926
+
927
+ # ========================================================================== #
928
+ # === @array_missing_components
929
+ #
930
+ # This Array will keep track of all components that are missing on the
931
+ # given system.
932
+ # ========================================================================== #
933
+ @array_missing_components = []
934
+
935
+ # ========================================================================== #
936
+ # === EnvironmentInformation.clear_array_missing_components
937
+ # ========================================================================== #
938
+ def self.clear_array_missing_components
939
+ @array_missing_components
940
+ end; self.instance_eval { alias clear_missing_components clear_array_missing_components } # === EnvironmentInformation.clear_missing_components
941
+
942
+ # ========================================================================== #
943
+ # === EnvironmentInformation.register_this_component_is_missing
944
+ #
945
+ # The ideal input to this method is a Symbol, so that the Array
946
+ # stores only missing components that way.
947
+ # ========================================================================== #
948
+ def self.register_this_component_is_missing(i)
949
+ # ======================================================================== #
950
+ # First check if we have a Symbol as input:
951
+ # ======================================================================== #
952
+ if i.is_a? Symbol
953
+ copy = i.to_s
954
+ if copy.include?('_')
955
+ i = copy.split('_').last.to_sym
956
+ end
957
+ end
958
+ i = i.to_sym unless i.is_a? Symbol
959
+ # ======================================================================== #
960
+ # Do not register the same missing component twice:
961
+ # ======================================================================== #
962
+ unless @array_missing_components.include? i
963
+ @array_missing_components << i
964
+ end
965
+ end
966
+
967
+ # ========================================================================== #
968
+ # === EnvironmentInformation.is_this_component_missing?
969
+ # ========================================================================== #
970
+ def self.is_this_component_missing?(i)
971
+ !@array_missing_components.include?(i)
972
+ end
973
+
974
+ # ========================================================================== #
975
+ # === EnvironmentInformation.return_pkgconfig_based_programs
976
+ #
977
+ # This method will return all programs that are handled by pkgconfig.
978
+ #
979
+ # In March 2024, 150 programs depended on pkg-config (.pc files).
980
+ # ========================================================================== #
981
+ def self.return_pkgconfig_based_programs(
982
+ this_file = ::EnvironmentInformation.file_query_to_use_for_the_individual_components
983
+ )
984
+ dataset = YAML.load_file(this_file)
985
+ return dataset.select {|key, value|
986
+ # ====================================================================== #
987
+ # The next query will select both :pkgconfig and :"pkg-config".
988
+ # ====================================================================== #
989
+ value.to_s.start_with? 'pkg'
990
+ }.keys
991
+ end
992
+
993
+ # ========================================================================= #
994
+ # === EnvironmentInformation.autogenerate_all_relevant_methods
995
+ #
996
+ # By default this method will scan for all tracked programs, and
997
+ # for the xorg-components.
998
+ # ========================================================================= #
999
+ def self.autogenerate_all_relevant_methods(
1000
+ i = tracked_components?
1001
+ )
1002
+ i.flatten!
1003
+ # ======================================================================= #
1004
+ # Add some aliases which will be defined next.
1005
+ # ======================================================================= #
1006
+ hash_aliases = {
1007
+ atk: :libatk, # === EnvironmentInformation.return_version_of_libatk
1008
+ pcre2: :libpcre2, # === EnvironmentInformation.return_version_of_libpcre2
1009
+ pcre: :libpcre, # === EnvironmentInformation.return_version_of_libpcre
1010
+ zlib: :libzlib # === EnvironmentInformation.return_version_of_libzlib
1011
+ }
1012
+ # ======================================================================= #
1013
+ # Iterate over our Array next:
1014
+ # ======================================================================= #
1015
+ i.each {|this_program|
1016
+ case this_program
1017
+ when :kde
1018
+ this_program = :kde_frameworks
1019
+ end
1020
+ self.class.instance_eval {
1021
+ # =================================================================== #
1022
+ # To test this method, try to do:
1023
+ #
1024
+ # EnvironmentInformation.return_version_of_valgrind # => "3.15.0"
1025
+ #
1026
+ # =================================================================== #
1027
+ this_method = "return_version_of_#{this_program}"
1028
+ define_method(this_method) {
1029
+ return_version_of_this_program(this_program)
1030
+ }
1031
+ if hash_aliases.has_key?(this_program)
1032
+ # ================================================================= #
1033
+ # To test this, try:
1034
+ #
1035
+ # EnvironmentInformation.return_version_of_libzlib
1036
+ #
1037
+ # ================================================================= #
1038
+ use_this_as_the_alias_target = "return_version_of_#{hash_aliases[this_program]}"
1039
+ define_method(use_this_as_the_alias_target) {
1040
+ return_version_of_this_program(this_program)
1041
+ }
1042
+ end
1043
+ }
1044
+ }
1045
+ end
1046
+
1047
+ # autogenerate_all_relevant_methods # ← And call it at once. No longer as of 2024.
1048
+
1049
+ # ========================================================================== #
1050
+ # And add a few more aliases. This list may have to be revisited again at
1051
+ # a later time.
1052
+ # ========================================================================== #
1053
+ # self.instance_eval { alias add_xz_information return_version_of_xz } # === EnvironmentInformation.add_xz_information
1054
+ # self.instance_eval { alias append_xz_version return_version_of_xz } # === EnvironmentInformation.append_xz_version
1055
+ # self.instance_eval { alias return_version_of_sed? return_version_of_sed } # === EnvironmentInformation.return_version_of_sed?
1056
+ # self.instance_eval { alias return_version_of_makeinfo return_version_of_texinfo } # === EnvironmentInformation.return_version_of_makeinfo
1057
+ # self.instance_eval { alias xfsprogs? return_version_of_xfsprogs } # === EnvironmentInformation.xfsprogs?
1058
+ # self.instance_eval { alias add_xfsprogs_information return_version_of_xfsprogs } # === EnvironmentInformation.add_xfsprogs_information
1059
+ # self.instance_eval { alias return_version_of_lftp? return_version_of_lftp } # === EnvironmentInformation.return_version_of_lftp?
1060
+ # self.instance_eval { alias add_llvm_information return_version_of_llvm } # === EnvironmentInformation.add_llvm_information
1061
+ # self.instance_eval { alias append_llvm_version return_version_of_llvm } # === EnvironmentInformation.append_llvm_version
1062
+ # self.instance_eval { alias add_mpc_information return_version_of_mpc } # === EnvironmentInformation.add_mpc_information
1063
+ # self.instance_eval { alias append_mpc_version return_version_of_mpc } # === EnvironmentInformation.append_mpc_version
1064
+ # self.instance_eval { alias try_to_show_re2c_version return_version_of_re2c } # === EnvironmentInformation.try_to_show_re2c_version
1065
+ # self.instance_eval { alias append_re2c_version return_version_of_re2c } # === EnvironmentInformation.append_nasm_version
1066
+ # self.instance_eval { alias return_version_of_pkg_config return_version_of_pkgconfig } # === EnvironmentInformation.return_version_of_pkg_config
1067
+ # self.instance_eval { alias add_readline_information return_version_of_readline } # === EnvironmentInformation.add_readline_information
1068
+ # self.instance_eval { alias append_readline_version return_version_of_readline } # === EnvironmentInformation.add_readline_information
1069
+ # self.instance_eval { alias return_version_of_liblibtasn1 return_version_of_libtasn1 } # === EnvironmentInformation.return_version_of_liblibtasn1
1070
+ # self.instance_eval { alias return_version_of_liblibtasn return_version_of_libtasn1 } # === EnvironmentInformation.return_version_of_liblibtasn
1071
+ # self.instance_eval { alias return_version_of_grep? return_version_of_grep } # === EnvironmentInformation.return_version_of_grep?
1072
+ # self.instance_eval { alias return_version_of_intltool? return_version_of_intltool } # === EnvironmentInformation.return_version_of_intltool?
1073
+ # self.instance_eval { alias glib? return_version_of_glib } # === EnvironmentInformation.glib?
1074
+ # self.instance_eval { alias add_gmp_information return_version_of_gmp } # === EnvironmentInformation.add_gmp_information
1075
+ # self.instance_eval { alias append_gmp_version return_version_of_gmp } # === EnvironmentInformation.append_gmp_version
1076
+ # self.instance_eval { alias kernel return_version_of_linux } # === EnvironmentInformation.kernel
1077
+ # self.instance_eval { alias linux_kernel return_version_of_linux } # === EnvironmentInformation.linux_kernel
1078
+ # self.instance_eval { alias linux_kernel? return_version_of_linux } # === EnvironmentInformation.linux_kernel?
1079
+ # self.instance_eval { alias return_information_about_the_component_called_linux_kernel return_version_of_linux } # === EnvironmentInformation.return_information_about_the_component_called_linux_kernel
1080
+ # self.instance_eval { alias append_kernel_version return_version_of_linux } # === EnvironmentInformation.append_kernel_version
1081
+ # self.instance_eval { alias add_kernel_information return_version_of_linux } # === EnvironmentInformation.add_kernel_information
1082
+ # self.instance_eval { alias return_version_of_linux_kernel return_version_of_linux } # === EnvironmentInformation.return_version_of_linux_kernel
1083
+ # self.instance_eval { alias return_version_of_linux_kernel? return_version_of_linux } # === EnvironmentInformation.return_version_of_linux_kernel?
1084
+ # self.instance_eval { alias boost? return_version_of_boost } # === EnvironmentInformation.boost?
1085
+ # self.instance_eval { alias return_version_of_boost? return_version_of_boost } # === EnvironmentInformation.return_version_of_boost?
1086
+ # self.instance_eval { alias return_version_of_find return_version_of_findutils } # === EnvironmentInformation.return_version_of_find
1087
+ # self.instance_eval { alias findutils? return_version_of_findutils } # === EnvironmentInformation.findutils?
1088
+ # self.instance_eval { alias awk? return_version_of_gawk } # === EnvironmentInformation.awk?
1089
+ # self.instance_eval { alias gawk? return_version_of_gawk } # === EnvironmentInformation.gawk?
1090
+ # self.instance_eval { alias return_information_about_the_component_called_awk return_version_of_gawk } # === EnvironmentInformation.return_information_about_the_component_called_awk
1091
+ # self.instance_eval { alias return_version_of_awk? return_version_of_gawk } # === EnvironmentInformation.return_version_of_awk?
1092
+ # self.instance_eval { alias return_version_of_awk return_version_of_gawk } # === EnvironmentInformation.return_version_of_awk
1093
+ # self.instance_eval { alias append_gdkpixbuf_version return_version_of_gdkpixbuf } # === EnvironmentInformation.append_gdkpixbuf_version
1094
+ # self.instance_eval { alias glibc? return_version_of_glibc } # === EnvironmentInformation.glibc?
1095
+ # self.instance_eval { alias glibc_version? return_version_of_glibc } # === EnvironmentInformation.glibc_version?
1096
+ # self.instance_eval { alias return_version_of_glibc? return_version_of_glibc } # === EnvironmentInformation.return_version_of_glibc?
1097
+ # self.instance_eval { alias ruby? return_version_of_ruby } # === EnvironmentInformation.ruby?
1098
+ # self.instance_eval { alias return_information_about_the_component_called_ruby return_version_of_ruby } # === EnvironmentInformation.return_information_about_the_component_called_ruby
1099
+ # self.instance_eval { alias return_version_of_ruby? return_version_of_ruby } # === EnvironmentInformation.return_version_of_ruby?
1100
+ # self.instance_eval { alias binutils? return_version_of_binutils } # === EnvironmentInformation.binutils?
1101
+ # self.instance_eval { alias return_version_of_binutils? return_version_of_binutils } # === EnvironmentInformation.return_version_of_binutils?
1102
+ # self.instance_eval { alias bison? return_version_of_bison } # === EnvironmentInformation.bison?
1103
+ # self.instance_eval { alias return_version_of_bison? return_version_of_bison } # === EnvironmentInformation.return_version_of_bison?
1104
+ # self.instance_eval { alias return_version_of_flex? return_version_of_flex } # === EnvironmentInformation.return_version_of_flex?
1105
+ # self.instance_eval { alias return_version_of_freetype2 return_version_of_freetype } # === EnvironmentInformation.return_version_of_freetype2
1106
+ # self.instance_eval { alias evince? return_version_of_evince } # === EnvironmentInformation.evince?
1107
+ # self.instance_eval { alias return_version_of_evince? return_version_of_evince } # === EnvironmentInformation.return_version_of_evince?
1108
+ # self.instance_eval { alias gcc? return_version_of_gcc } # === EnvironmentInformation.gcc?
1109
+ # self.instance_eval { alias return_information_about_the_component_called_gcc return_version_of_gcc } # === EnvironmentInformation.return_information_about_the_component_called_gcc
1110
+ # self.instance_eval { alias return_version_of_gcc? return_version_of_gcc } # === EnvironmentInformation.return_version_of_gcc?
1111
+ # self.instance_eval { alias return_version_of_R return_version_of_r } # === EnvironmentInformation.return_version_of_R
1112
+ # self.instance_eval { alias coreutils? return_version_of_coreutils } # === EnvironmentInformation.coreutils?
1113
+ # self.instance_eval { alias return_version_of_coreutils? return_version_of_coreutils } # === EnvironmentInformation.return_version_of_coreutils
1114
+ # self.instance_eval { alias return_version_of_diffutils? return_version_of_diffutils } # === EnvironmentInformation.return_version_of_diffutils?
1115
+ # self.instance_eval { alias return_version_of_libexempi return_version_of_exempi } # === EnvironmentInformation.return_version_of_libexempi
1116
+ # self.instance_eval { alias return_version_of_gpg return_version_of_gnupg } # === EnvironmentInformation.return_version_of_gpg
1117
+ # self.instance_eval { alias return_version_of_gnupg? return_version_of_gnupg } # === EnvironmentInformation.return_version_of_gnupg?
1118
+ # self.instance_eval { alias return_version_of_bzip return_version_of_bzip2 } # === EnvironmentInformation.return_version_of_bzip
1119
+ # self.instance_eval { alias return_version_of_llvm return_version_of_clang } # === EnvironmentInformation.return_version_of_llvm
1120
+ # self.instance_eval { alias return_clang_version return_version_of_clang } # === EnvironmentInformation.return_clang_version
1121
+ # self.instance_eval { alias kde5? return_version_of_kde_frameworks } # === EnvironmentInformation.kde5?
1122
+ # self.instance_eval { alias add_kde5_information return_version_of_kde_frameworks } # === EnvironmentInformation.add_kde5_information
1123
+ # self.instance_eval { alias add_kde_information return_version_of_kde_frameworks } # === EnvironmentInformation.add_kde_information
1124
+ # self.instance_eval { alias return_information_about_the_component_called_rubygems return_version_of_rubygems } # === EnvironmentInformation.return_information_about_the_component_called_rubygems
1125
+ # self.instance_eval { alias rubygems? return_version_of_rubygems } # === EnvironmentInformation.rubygems?
1126
+ # self.instance_eval { alias return_version_of_rubygems? return_version_of_rubygems } # === EnvironmentInformation.return_version_of_rubygems?
1127
+ # self.instance_eval { alias gtk3? return_version_of_gtk3 } # === EnvironmentInformation.gtk3?
1128
+ # self.instance_eval { alias gtk2? return_version_of_gtk2 } # === EnvironmentInformation.gtk2?
1129
+
1130
+ # ========================================================================== #
1131
+ # === EnvironmentInformation.start_gtk_component
1132
+ #
1133
+ # We have to rescue the code so to notify the user what exactly
1134
+ # may have failed.
1135
+ # ========================================================================== #
1136
+ def self.start_gtk_component
1137
+ begin
1138
+ this_file = 'environment_information/gui/gtk3/environment_information.rb'
1139
+ require this_file
1140
+ rescue LoadError => error
1141
+ e "An error happened - file #{sfile(this_file)} could not be found."
1142
+ pp error
1143
+ end
1144
+ ::EnvironmentInformation.run_gtk
1145
+ end
1146
+
1147
+ # ========================================================================= #
1148
+ # === EnvironmentInformation.return_version_of_this_program
1149
+ #
1150
+ # This is the general method that will return the version of a particular
1151
+ # program at hand.
1152
+ #
1153
+ # The method must be able to deal with using pkg-config, but also
1154
+ # querying some program's version via --version, via the commandline,
1155
+ # Furthermore, some programs may require an ad-hoc fix.
1156
+ # ========================================================================= #
1157
+ def self.return_version_of_this_program(
1158
+ this_program,
1159
+ prefix_to_use = @prefix_to_use
1160
+ )
1161
+ prefix_to_use = prefix_to_use.dup if prefix_to_use
1162
+ version = nil # ← This is the default.
1163
+ if this_program.is_a? Array
1164
+ this_program = this_program.flatten.first
1165
+ end
1166
+ # ======================================================================= #
1167
+ # Next define a few aliases.
1168
+ # ======================================================================= #
1169
+ this_program = ::EnvironmentInformation.return_alias_to(this_program)
1170
+ if ARRAY_TRACKED_NON_PROGRAMS.include? this_program
1171
+ return ::EnvironmentInformation.send(this_program)
1172
+ elsif @query_to_use_for_the_individual_components.has_key? this_program.to_sym
1173
+ use_this_command = @query_to_use_for_the_individual_components[this_program.to_sym]
1174
+ case use_this_command
1175
+ # ===================================================================== #
1176
+ # === :mate_desktop
1177
+ #
1178
+ # This entry is special.
1179
+ # ===================================================================== #
1180
+ when :mate_desktop
1181
+ return RBT.return_mate_desktop_version_array
1182
+ # ===================================================================== #
1183
+ # === :pkgconfig
1184
+ #
1185
+ # An invocation example for this would be:
1186
+ #
1187
+ # x = EnvironmentInformation.return_version_of_this_program(:check) # => "0.15.2"
1188
+ #
1189
+ # ===================================================================== #
1190
+ when :pkgconfig
1191
+ version = ::EnvironmentInformation::Queries::PkgConfig.new(this_program).version?
1192
+ # ===================================================================== #
1193
+ # === :custom_gtk2
1194
+ # ===================================================================== #
1195
+ when :custom_gtk2
1196
+ version = ::EnvironmentInformation::Queries::PkgConfig.new('gtk+-2.0').version?
1197
+ # ===================================================================== #
1198
+ # === :custom_mpc
1199
+ #
1200
+ # We rely on the header called mpc.h.
1201
+ # ===================================================================== #
1202
+ when :custom_mpc
1203
+ version = ::EnvironmentInformation.return_version_of_mpc
1204
+ # ===================================================================== #
1205
+ # === :custom_boost
1206
+ # ===================================================================== #
1207
+ when :custom_boost
1208
+ version = ::EnvironmentInformation.return_version_of_boost
1209
+ if version.nil?
1210
+ register_this_component_is_missing(:boost)
1211
+ end
1212
+ # ===================================================================== #
1213
+ # === :version (version tag)
1214
+ #
1215
+ # This entry point is typically for "program_name --version"
1216
+ # entries. Some of them require custom modifications.
1217
+ # ===================================================================== #
1218
+ when :version
1219
+ # =================================================================== #
1220
+ # Next enable support for AppDir layout, where programs will
1221
+ # ultimately reside in the same directory.
1222
+ # =================================================================== #
1223
+ unless prefix_to_use.empty?
1224
+ prefix_to_use << "#{this_program.to_s.capitalize}/Current/bin/"
1225
+ end
1226
+ cmd = "#{prefix_to_use}#{this_program} --version #{ERROR_LINE}"
1227
+ if @debug
1228
+ e Colours.crimson('DEBUG for the prefix-value in use: ')+
1229
+ Colours.steelblue(cmd)
1230
+ end
1231
+ version = ::EnvironmentInformation::Queries::SimpleVersion.new(this_program) {{
1232
+ prefix_to_use: prefix_to_use
1233
+ }}.version?
1234
+ # ===================================================================== #
1235
+ # Next we will handle special programs, such as "swig -v" and similar.
1236
+ # This is done by class ComplexVersion since as of 29.08.2020.
1237
+ # ===================================================================== #
1238
+ else # else tag
1239
+ if use_this_command.start_with?('pkg-config')
1240
+ version = ::EnvironmentInformation::Queries::PkgConfig.new(this_program).version?
1241
+ else
1242
+ cmd = "#{@prefix_to_use}#{use_this_command} #{ERROR_LINE}"
1243
+ version = ::EnvironmentInformation::Queries::ComplexVersion.new(this_program) {{
1244
+ prefix_to_use: prefix_to_use
1245
+ }}.version?
1246
+ end
1247
+ end
1248
+ else
1249
+ e 'Not registered any key for the program: '+this_program.to_s
1250
+ e 'This is currently not allowed - please add this missing information.'
1251
+ exit
1252
+ end
1253
+ result = version
1254
+ if result
1255
+ unless result.include? COMMAND_NOT_FOUND
1256
+ result = result.dup if result.frozen?
1257
+ result.strip!
1258
+ end
1259
+ end
1260
+ if result and (result == 'found' or result == 'foud')
1261
+ register_this_component_is_missing(this_program)
1262
+ elsif result and result.include?(COMMAND_NOT_FOUND)
1263
+ register_this_component_is_missing(this_program)
1264
+ # ======================================================================= #
1265
+ # Check whether pkg-config is available or not.
1266
+ # ======================================================================= #
1267
+ elsif result and (
1268
+ result.include?(PKGCONFIG_COMMAND_NOT_FOUND) or
1269
+ result.include?(NO_SUCH_FILE_OR_DIRECTORY)
1270
+ )
1271
+ register_this_component_is_missing(this_program)
1272
+ elsif result.nil?
1273
+ register_this_component_is_missing(this_program)
1274
+ end
1275
+ return result
1276
+ end; self.instance_eval { alias version_for? return_version_of_this_program } # === EnvironmentInformation,version_for?
1277
+
1278
+ # ========================================================================== #
1279
+ # === EnvironmentInformation.return_version_of_this_program
1280
+ #
1281
+ # This method will try to use --version first.
1282
+ #
1283
+ # This will typically use the main binary at hand, which we thus expect
1284
+ # to respond to --version.
1285
+ #
1286
+ # Note that the method will also handle input that can NOT be generated
1287
+ # via --version. This is usually called a "complex" version query, as
1288
+ # far as the environment_information gem is concerned.
1289
+ #
1290
+ # Usage example:
1291
+ #
1292
+ # EnvironmentInformation.return_version_of_this_program(:ccache)
1293
+ #
1294
+ # ========================================================================== #
1295
+ def self.return_version_of_this_program(
1296
+ i,
1297
+ &block
1298
+ )
1299
+ prefix_to_use = ''.dup
1300
+ i = i.to_sym
1301
+ # ======================================================================== #
1302
+ # === Handle blocks given to this method next
1303
+ # ======================================================================== #
1304
+ if block_given?
1305
+ yielded = yield
1306
+ if yielded.is_a? Hash
1307
+ # ======================================================================== #
1308
+ # === :prefix_to_use
1309
+ # ======================================================================== #
1310
+ if yielded.has_key? :prefix_to_use
1311
+ prefix_to_use << yielded.delete(:prefix_to_use)
1312
+ end
1313
+ end
1314
+ end
1315
+ # ======================================================================== #
1316
+ # The next variable will store the Hash containing all individual
1317
+ # queries for the registered programs.
1318
+ #
1319
+ # For instance:
1320
+ #
1321
+ # :busybox=>:custom_busybox, :bzip2=>:"bzip2recover --version",
1322
+ # :cairo=>:pkgconfig, :ccache=>:version, :check=>:pkgconfig,
1323
+ # :clang=>:version, :clutter=>:"pkg-config --modversion clutter-1.0",
1324
+ # :lighttpd=>:version # and so forth
1325
+ #
1326
+ # ======================================================================== #
1327
+ # _ = ::EnvironmentInformation.query_to_use_for_the_individual_components?
1328
+ _ = ::EnvironmentInformation.load_file_query_to_use_for_the_individual_components.transform_keys {|entry|
1329
+ entry.to_sym
1330
+ }
1331
+ if _.nil?
1332
+ _ = ::EnvironmentInformation.load_file_query_to_use_for_the_individual_components
1333
+ end
1334
+ if _.has_key?(i) # Check whether the program is registered.
1335
+ result = _[i]
1336
+ case result.to_sym
1337
+ # ====================================================================== #
1338
+ # === :version
1339
+ #
1340
+ # This is the simplest entry point; we will try the commandline flag
1341
+ # "--version" here. If you have to use "-v" then use :short_version
1342
+ # instead.
1343
+ # ====================================================================== #
1344
+ when :version
1345
+ program_version = silent_sys_command("#{prefix_to_use}#{i} --version").strip
1346
+ # ====================================================================== #
1347
+ # === :short_version
1348
+ # ====================================================================== #
1349
+ when :short_version,
1350
+ :simple_version
1351
+ program_version = silent_sys_command("#{prefix_to_use}#{i} -v").strip
1352
+ # ====================================================================== #
1353
+ # === :custom_busybox
1354
+ # ====================================================================== #
1355
+ when :custom_busybox
1356
+ program_version = ::EnvironmentInformation.return_version_of_busybox
1357
+ # ====================================================================== #
1358
+ # === :custom_xrandr
1359
+ # ====================================================================== #
1360
+ when :custom_xrandr
1361
+ program_version = ::EnvironmentInformation.return_version_of_xrandr
1362
+ # ====================================================================== #
1363
+ # === :custom_xvid
1364
+ # ====================================================================== #
1365
+ when :custom_xvid
1366
+ program_version = ::EnvironmentInformation.return_version_of_xvid
1367
+ # ====================================================================== #
1368
+ # === :custom_boost
1369
+ # ====================================================================== #
1370
+ when :custom_boost
1371
+ program_version = ::EnvironmentInformation.return_version_of_boost
1372
+ # ====================================================================== #
1373
+ # === :custom_mpc
1374
+ # ====================================================================== #
1375
+ when :custom_mpc
1376
+ program_version = ::EnvironmentInformation.return_version_of_mpc
1377
+ end
1378
+ if program_version.include?('not found') # First check whether it was found or not.
1379
+ program_version = ::EnvironmentInformation::NOT_FOUND
1380
+ else
1381
+ if program_version.include? N
1382
+ program_version = program_version.split(N).first
1383
+ end
1384
+ if program_version.include? '--'
1385
+ program_version.gsub!(/--/,'') # For strace specifically.
1386
+ end
1387
+ program_version = sanitize_this_program_version(program_version)
1388
+ # ======================================================================== #
1389
+ # Next handle cases such as the following two examples:
1390
+ #
1391
+ # "ffmpeg version 4.3.1 Copyright (c) 2000-2020 the FFmpeg developers"
1392
+ # "openjdk version \"14.0.2\" 2020-07-14"
1393
+ # "ffmpeg version n5.1.2 Copyright (c) 2000-2022 the FFmpeg developers"
1394
+ #
1395
+ # ======================================================================== #
1396
+ if program_version.include? ' version '
1397
+ program_version = program_version.scan(
1398
+ / version n?"?(\d{0,2}\.\d{1,2}\.?\d{0,2})"?/ # See: See: https://rubular.com/r/39cIQqXin2oco0
1399
+ ).flatten.first.to_s.strip
1400
+ end
1401
+ # ======================================================================== #
1402
+ # Next come format-entries such as:
1403
+ #
1404
+ # "lighttpd/1.4.71 - a light and fast webserver"
1405
+ #
1406
+ # This may fail, though - see vim:
1407
+ #
1408
+ # "VIM - Vi IMproved 9.0 (2022 Jun 28, compiled Mar 15 2024 11:08:54)"
1409
+ #
1410
+ # ======================================================================== #
1411
+ if program_version.include? ' - '
1412
+ unless this_program.to_s.include?('vim')
1413
+ program_version = program_version.split(' - ').first.to_s
1414
+ end
1415
+ end
1416
+ # ======================================================================== #
1417
+ # Next we will specifically handle vim:
1418
+ # ======================================================================== #
1419
+ if program_version =~ / (\d{1,2}\.\d{1,2}) \(/
1420
+ program_version = $1.to_s.dup
1421
+ end
1422
+ if program_version.include?('[') and program_version.include?(']')
1423
+ program_version.gsub!(/\[.+\]/, '')
1424
+ end
1425
+ program_version.strip!
1426
+ if program_version.start_with? "#{i} "
1427
+ # For example: "ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]"
1428
+ program_version.sub!(/#{i} /, '')
1429
+ elsif program_version.start_with? "#{i.upcase} "
1430
+ # For example: "NASM version 2.15.04 compiled on Aug 27 2020"
1431
+ program_version.sub!(/#{i.upcase} /, '')
1432
+ end
1433
+ # ======================================================================== #
1434
+ # The next check for "Version" should come after we eliminated
1435
+ # the leading program name.
1436
+ # ======================================================================== #
1437
+ if program_version.include? 'Version '
1438
+ program_version = program_version.scan(
1439
+ /Version (\d{0,2}\.?\d{0,2}\.\d{0,2})/
1440
+ ).flatten.first.to_s.dup
1441
+ elsif program_version.include? 'version '
1442
+ # This here should work for most programs, save for perl.
1443
+ program_version = program_version.scan(
1444
+ /version (\d{0,2}\.?\d{0,2}\.\d{0,2})/
1445
+ ).flatten.first.to_s.dup
1446
+ end
1447
+ if program_version.include? ' patchlevel '
1448
+ # ================================================================== #
1449
+ # Gnuplot has this specifically: "5.4 patchlevel 0"
1450
+ # ================================================================== #
1451
+ program_version = program_version.sub(/ patchlevel /,'.').strip
1452
+ end
1453
+ # ======================================================================== #
1454
+ # Next we kill everything inside (). This may sometimes be
1455
+ # problematic, which is why this check comes quite late.
1456
+ # ======================================================================== #
1457
+ if program_version.include?('(') and program_version.include?(')')
1458
+ program_version.gsub!(/\(.+\)/, '')
1459
+ end
1460
+ # ======================================================================== #
1461
+ # Handle: "IceWM 1.8.0, Copyright 1997-2003 Marko Macek, 2001 Mathias Hasselmann."
1462
+ # ======================================================================== #
1463
+ if program_version.include?(',')
1464
+ program_version = program_version.split(',').first
1465
+ end
1466
+ if program_version.include?('/')
1467
+ # ================================================================== #
1468
+ # Assume something like "lighttpd/1.4.71".
1469
+ # ================================================================== #
1470
+ program_version = program_version.split('/').last
1471
+ end
1472
+ # ======================================================================== #
1473
+ # Next, if a '-' is included, we split it and use the last part.
1474
+ # This handles cases such as "valgrind-3.16.0".
1475
+ # ======================================================================== #
1476
+ if program_version.include?('-')
1477
+ program_version = program_version.split('-').last
1478
+ end
1479
+ # ======================================================================== #
1480
+ # Last but not least, for "node" specifically.
1481
+ # ======================================================================== #
1482
+ if program_version.start_with? 'v'
1483
+ program_version[0,1] = ''
1484
+ end
1485
+ # ======================================================================== #
1486
+ # Handle cases such as: "nginx/1.18.0"
1487
+ # ======================================================================== #
1488
+ if program_version.include? '/'
1489
+ program_version = program_version.split('/').last.strip
1490
+ end
1491
+ if program_version.include? COMMAND_NOT_FOUND
1492
+ program_version = nil
1493
+ elsif program_version.include? ' '
1494
+ # ================================================================== #
1495
+ # Assume input such as: "GNU ld (GNU Binutils) 2.35"
1496
+ # ================================================================== #
1497
+ program_version = program_version.split(' ').last
1498
+ end
1499
+ end
1500
+ return program_version.strip
1501
+ end
1502
+ end; self.instance_eval { alias return_version_of return_version_of_this_program } # === EnvironmentInformation.return_version_of
1503
+
1504
+ # ========================================================================== #
1505
+ # === EnvironmentInformation.return_simple_version_based_programs
1506
+ #
1507
+ # This method will return an Array, consisting of all files that
1508
+ # can be queried via a simple --version query, via the commandline.
1509
+ # ========================================================================== #
1510
+ def self.return_simple_version_based_programs(
1511
+ i = file_query_to_use_for_the_individual_components
1512
+ )
1513
+ dataset = YAML.load_file(i)
1514
+ dataset.select {|key, value|
1515
+ value = value.to_sym
1516
+ # ===================================================================== #
1517
+ # The next query will select only for :version entries.
1518
+ # ===================================================================== #
1519
+ value == :version
1520
+ }.keys
1521
+ end
1522
+
1523
+ # ========================================================================== #
1524
+ # === EnvironmentInformation.array_missing_components?
1525
+ # ========================================================================== #
1526
+ def self.array_missing_components?
1527
+ @array_missing_components
1528
+ end; self.instance_eval { alias missing_components? array_missing_components? } # === EnvironmentInformation.missing_components?
1529
+ self.instance_eval { alias which_components_are_missing? array_missing_components? } # === EnvironmentInformation.which_components_are_missing?
1530
+
1531
+ # ========================================================================= #
1532
+ # === EnvironmentInformation.return_path_to_all_programs_file
1533
+ # ========================================================================= #
1534
+ def self.return_path_to_all_programs_file
1535
+ "#{temp_directory?}environment_information.yml"
1536
+ end
1537
+
1538
+ # ========================================================================= #
1539
+ # === EnvironmentInformation.show_detailed_information_about_all_available_components
1540
+ #
1541
+ # This method is mostly for testing purposes only; for real use
1542
+ # for the project you should consider making use of
1543
+ # Environment.silent_run instead.
1544
+ #
1545
+ # Do note that this method will always show all available components;
1546
+ # if you need more fine-tuned control then you have to use the
1547
+ # class EnvironmentInformation instead.
1548
+ # ========================================================================= #
1549
+ def self.show_detailed_information_about_all_available_components
1550
+ @hash_available_programs = {} # Clear it every time this method is run.
1551
+ work_on_these_programs = []
1552
+ work_on_these_programs << tracked_components?
1553
+ e
1554
+ work_on_these_programs.each {|this_program|
1555
+ version_of_this_program = ::EnvironmentInformation.return_version_of_this_program(this_program)
1556
+ # ===================================================================== #
1557
+ # Do a little sanitizing next:
1558
+ # ===================================================================== #
1559
+ case this_program.to_s
1560
+ when 'kde_frameworks'
1561
+ this_program = 'KDE Frameworks'.to_sym
1562
+ end
1563
+ left_side = colourize_and_pad_the_left_side(this_program)
1564
+ case version_of_this_program
1565
+ when COMMAND_NOT_FOUND,
1566
+ ''
1567
+ version_of_this_program = nil
1568
+ colour_for_the_right_side = :orange
1569
+ else
1570
+ colour_for_the_right_side = :notify_if_missing
1571
+ end
1572
+ # ===================================================================== #
1573
+ # Next register this program into the main hash.
1574
+ # ===================================================================== #
1575
+ @hash_available_programs[this_program] = version_of_this_program
1576
+ right_side = colourize_and_pad_the_right_side(
1577
+ version_of_this_program,
1578
+ colour_for_the_right_side
1579
+ )
1580
+ e " #{left_side} #{right_side}"
1581
+ }
1582
+ e
1583
+ # ======================================================================= #
1584
+ # Report missing programs.
1585
+ # ======================================================================= #
1586
+ _ = missing_components?
1587
+ unless _.empty?
1588
+ e 'The following components were not found:'
1589
+ e
1590
+ _.each {|this_component|
1591
+ e lightseagreen(" #{this_component}")
1592
+ }
1593
+ e
1594
+ end
1595
+ consider_storing_these_results_into_a_local_file
1596
+ end; self.instance_eval { alias test show_detailed_information_about_all_available_components } # === EnvironmentInformation.test
1597
+
1598
+ # ========================================================================= #
1599
+ # === EnvironmentInformation.return_array_of_outdated_programs
1600
+ #
1601
+ # This method will return all programs that are outdated - this
1602
+ # also includes missing programs, so the method name is a slight
1603
+ # misnomer.
1604
+ #
1605
+ # Usage example:
1606
+ #
1607
+ # EnvironmentInformation.initialize
1608
+ # array = EnvironmentInformation.return_array_of_outdated_programs
1609
+ #
1610
+ # ========================================================================= #
1611
+ def self.return_array_of_outdated_programs(
1612
+ hash = ::EnvironmentInformation.hash?
1613
+ )
1614
+ forbidden = ::EnvironmentInformation.load_file_array_tracked_non_programs
1615
+ # ======================================================================= #
1616
+ # Now find all entries that are either nil, or have a too low program
1617
+ # version.
1618
+ # ======================================================================= #
1619
+ array = hash.select {|key, value|
1620
+ if value and forbidden.include?(key) # ← we exclude entries here such as "rubygems_installation_dir".
1621
+ false
1622
+ else
1623
+ if value.nil? or value.include?('not found') or
1624
+ !(value =~ /\d+/) # ← check for at the least one number, such as "1".
1625
+ true
1626
+ else
1627
+ false
1628
+ end
1629
+ end
1630
+ }.keys
1631
+ # ======================================================================= #
1632
+ # Next, check these against the local program version:
1633
+ # local_program_version = key
1634
+ # ======================================================================= #
1635
+ return array
1636
+ end
1637
+
1638
+ # ========================================================================= #
1639
+ # === Environment.silent_run
1640
+ # ========================================================================= #
1641
+ def self.silent_run
1642
+ _ = ::EnvironmentInformation.new { :do_not_run_yet }
1643
+ _.be_silent
1644
+ _.run
1645
+ return _.hash?
1646
+ end; self.instance_eval { alias build_up_and_return_the_main_hash silent_run } # === EnvironmentInformation.build_up_and_return_the_main_hash
1647
+ self.instance_eval { alias initialize_hash silent_run } # === EnvironmentInformation.initialize_hash
1648
+ self.instance_eval { alias initialize silent_run } # === EnvironmentInformation.initialize
1649
+ self.instance_eval { alias run silent_run } # === EnvironmentInformation.run
1650
+
1651
+ # ========================================================================== #
1652
+ # === EnvironmentInformation.store_this_hash_into_a_local_file
1653
+ #
1654
+ # This method will always take the dataset stored in the main Hash when
1655
+ # saving the yaml file at hand.
1656
+ #
1657
+ # The file will be stored under the temp_directory.
1658
+ #
1659
+ # This variant is silent by default.
1660
+ # ========================================================================== #
1661
+ def self.store_this_hash_into_a_local_file(
1662
+ hash = hash_available_programs?,
1663
+ this_file = return_path_to_all_programs_file,
1664
+ be_verbose = false
1665
+ )
1666
+ unless hash.empty?
1667
+ what = YAML.dump(hash)
1668
+ e "#{rev}Storing these #{royalblue(hash.size)} "\
1669
+ "#{rev}components into: #{sfile(this_file)}" if be_verbose
1670
+ ::EnvironmentInformation.write_what_into(what, this_file)
1671
+ end
1672
+ end; self.instance_eval { alias consider_storing_these_results_into_a_local_file store_this_hash_into_a_local_file } # === EnvironmentInformation.consider_storing_these_results_into_a_local_file
1673
+ self.instance_eval { alias store_relevant_files store_this_hash_into_a_local_file } # === EnvironmentInformation.store_relevant_files
1674
+
1675
+ # ========================================================================= #
1676
+ # === EnvironmentInformation.return_everything
1677
+ # ========================================================================= #
1678
+ def self.return_everything
1679
+ require 'environment_information/main_class/main_class.rb'
1680
+ _ = ::EnvironmentInformation.new(:do_not_run_yet)
1681
+ _.disable_colours
1682
+ _.be_quiet
1683
+ _.menu('--really-everything')
1684
+ _.run
1685
+ return _.string
1686
+ end
1687
+
1688
+ # ========================================================================== #
1689
+ # === EnvironmentInformation.sanitize_this_version_string (sanitize tag)
1690
+ # ========================================================================== #
1691
+ def self.sanitize_this_version_string(
1692
+ i = nil
1693
+ )
1694
+ return if i.nil?
1695
+ if i.frozen?
1696
+ i = i.dup
1697
+ end
1698
+ # ======================================================================== #
1699
+ # === Handle ccache next:
1700
+ # ======================================================================== #
1701
+ if i.include? 'ccache version ' # Example: ccache version 4.8.2
1702
+ i = i.scan(/ccache version (\d{1,2}\.\d{1,2}\.\d{1,2})/).flatten.first.to_s
1703
+ end
1704
+ # ======================================================================== #
1705
+ # === Handle strace next:
1706
+ # ======================================================================== #
1707
+ if i.include? 'strace -- version '
1708
+ i = i.split('strace -- version ').last
1709
+ end
1710
+ # ======================================================================== #
1711
+ # === Handle glslang next
1712
+ #
1713
+ # We must handle e. g. 'Glslang Version: 11:14.0.0'
1714
+ # ======================================================================== #
1715
+ if i.include?('Glslang Version') and i.include?(':')# e. g. for glslang.
1716
+ i = i.split("\n").first if i.include? "\n"
1717
+ i = i.split(':').last.to_s.strip
1718
+ end
1719
+ # ======================================================================== #
1720
+ # === HMMER: we handle hmmer next here
1721
+ # ======================================================================== #
1722
+ if i.include? '# HMMER ' # ← Specifically for "hammer", e. g. 'HMMER 3.4 (Aug 2023); http://hmmer.org/'
1723
+ i = i.scan(
1724
+ /# HMMER (\d{0,2}\.\d{0,2}\.?\d{0,2})/
1725
+ ).flatten.first.to_s
1726
+ end
1727
+ # ======================================================================== #
1728
+ # === Handle xstdcmap next:
1729
+ # ======================================================================== #
1730
+ if i.include? 'xstdcmap '
1731
+ i = i.split('xstdcmap').last.strip
1732
+ end
1733
+ # ======================================================================== #
1734
+ # === Handle qpdf next:
1735
+ # ======================================================================== #
1736
+ if i.include? 'qpdf version '
1737
+ i = i.split('qpdf version ').last.strip
1738
+ end
1739
+ # ======================================================================== #
1740
+ # === Handle Swig next:
1741
+ # ======================================================================== #
1742
+ if i.include? 'SWIG Version'
1743
+ i = i.scan(
1744
+ /SWIG Version (\d{1,2}\.\d{1,2}\.\d{1,2})/
1745
+ ).flatten.first
1746
+ end
1747
+ # ======================================================================== #
1748
+ # === Handle Screen next
1749
+ #
1750
+ # For: Screen version 4.09.01 (GNU) 20-Aug-23
1751
+ # ======================================================================== #
1752
+ if i.include? 'Screen version'
1753
+ i = i.scan(
1754
+ /Screen version (\d{1,2}\.\d{1,2}\.\d{1,2})/
1755
+ ).flatten.first
1756
+ end
1757
+ # ======================================================================== #
1758
+ # === Handle valgrind next:
1759
+ # ======================================================================== #
1760
+ if i.include? 'valgrind-'
1761
+ i = i.split('-').last
1762
+ end
1763
+ # ======================================================================== #
1764
+ # === Handle gimp next:
1765
+ #
1766
+ # The String may look like this: 'GNU Image Manipulation Program version 2.10.36'
1767
+ # ======================================================================== #
1768
+ if i.include?('GNU Image Manipulation')
1769
+ i = i.scan(
1770
+ /GNU Image Manipulation Program version (\d{1,2}\.\d{1,2}\.\d{1,2})/
1771
+ ).flatten.first
1772
+ end
1773
+ # ======================================================================== #
1774
+ # === Handle IceWM here.
1775
+ #
1776
+ # The specific substring is:
1777
+ #
1778
+ # "IceWM 3.4.7, Copyright 1997-2012 Marko Macek, 2001 Mathias Hasselmann."
1779
+ #
1780
+ # ======================================================================== #
1781
+ if i.include? 'IceWM '
1782
+ i = i.scan(
1783
+ /IceWM (\d{1,2}\.\d{1,2}\.\d{1,2})/
1784
+ ).flatten.first.to_s
1785
+ end
1786
+ # ======================================================================== #
1787
+ # === Handle 'KDE Frameworks: 5.73.0'
1788
+ # ======================================================================== #
1789
+ if i.include? 'KDE Frameworks: '
1790
+ i = i.scan(
1791
+ /KDE Frameworks: (\d{0,2}\.\d{0,3}\.\d{0,2})/ # Must match e. g. "KDE Frameworks: 5.115.0".
1792
+ ).flatten.first.to_s
1793
+ end
1794
+ # ======================================================================== #
1795
+ # === Handle 'lighttpd' next
1796
+ # ======================================================================== #
1797
+ if i.include? '- a light and fast webserver'
1798
+ i = i.split('- a light and fast webserver').first
1799
+ i = i.split('/').last if i.include?('/')
1800
+ end
1801
+ # ======================================================================== #
1802
+ # === Handle flatpak next:
1803
+ # ======================================================================== #
1804
+ if i.include? 'Flatpak '
1805
+ i = i.split('Flatpak ').last
1806
+ end
1807
+ # ======================================================================== #
1808
+ # === Handle xinput next:
1809
+ # ======================================================================== #
1810
+ if i.include? 'xinput version '
1811
+ i = i.split(' ').last
1812
+ end
1813
+ # ======================================================================== #
1814
+ # === Handle vim next
1815
+ # ======================================================================== #
1816
+ if i.include? 'IMproved ' # For Vim.
1817
+ i = i.scan(
1818
+ /VIM - Vi IMproved (\d{1,2}\.\d{1,2})/
1819
+ ).flatten.first
1820
+ end
1821
+ # ======================================================================== #
1822
+ # === Handle xfs next:
1823
+ # ======================================================================== #
1824
+ if i.include? 'xfs_info'
1825
+ i.sub!(/xfs_info/,'')
1826
+ end
1827
+ # ======================================================================== #
1828
+ # === Handle rsync next:
1829
+ # ======================================================================== #
1830
+ if i.include? 'rsync version '
1831
+ i = i.split('rsync version ').last
1832
+ i = i.split(' ').first if i.include?(' ')
1833
+ end
1834
+ # ======================================================================== #
1835
+ # === Handle clang next:
1836
+ # ======================================================================== #
1837
+ if i.include? 'clang version ' # clang version 18.1.2
1838
+ i = i.split('clang version ').last.strip
1839
+ end
1840
+ # ======================================================================== #
1841
+ # === Handle git next:
1842
+ # ======================================================================== #
1843
+ if i.include? 'git version ' # git version
1844
+ i = i.split('git version ').last
1845
+ end
1846
+ # ======================================================================== #
1847
+ # === Handle gnuplot next:
1848
+ # ======================================================================== #
1849
+ if i.include? 'gnuplot ' # gnuplot version
1850
+ i = i.split('gnuplot ').last
1851
+ end
1852
+ # ======================================================================== #
1853
+ # === Handle gperf next:
1854
+ # ======================================================================== #
1855
+ if i.include? 'gperf ' # gperf version
1856
+ i = i.split('gperf ').last
1857
+ end
1858
+ # ======================================================================== #
1859
+ # === Handle re2c next:
1860
+ # ======================================================================== #
1861
+ if i.include? 're2c '
1862
+ i = i.split('re2c ').last
1863
+ end
1864
+ # ======================================================================== #
1865
+ # === Handle plzip next:
1866
+ # ======================================================================== #
1867
+ if i.include? 'plzip '
1868
+ i = i.split('plzip ').last
1869
+ end
1870
+ # ======================================================================== #
1871
+ # === Handle PHP next:
1872
+ # ======================================================================== #
1873
+ if i.include? 'PHP '
1874
+ i = i.scan(
1875
+ /PHP (\d{1,2}\.\d{1,2}\.\d{1,2})/
1876
+ ).flatten.first
1877
+ end
1878
+ # ======================================================================== #
1879
+ # === Handle dhcpcd next:
1880
+ # ======================================================================== #
1881
+ if i.include? 'dhcpcd '
1882
+ i = i.split('dhcpcd ').last
1883
+ end
1884
+ # ======================================================================== #
1885
+ # === Handle bubblewrap next:
1886
+ # ======================================================================== #
1887
+ if i.include? 'bubblewrap '
1888
+ i = i.split('bubblewrap ').last
1889
+ end
1890
+ # ======================================================================== #
1891
+ # === Handle cmake next:
1892
+ # ======================================================================== #
1893
+ if i.include? 'cmake version '
1894
+ i = i.split('cmake version ').last
1895
+ elsif i.include? 'cmake '
1896
+ i = i.split('cmake ').last
1897
+ end
1898
+ # ======================================================================== #
1899
+ # === Handle flex next:
1900
+ # ======================================================================== #
1901
+ if i.include? 'flex '
1902
+ i = i.split('flex ').last
1903
+ end
1904
+ # ======================================================================== #
1905
+ # === Handle file next:
1906
+ # ======================================================================== #
1907
+ if i.include? 'file-'
1908
+ i = i.split('file-').last
1909
+ end
1910
+ # ======================================================================== #
1911
+ # === Handle gzip next:
1912
+ # ======================================================================== #
1913
+ if i.include? 'gzip '
1914
+ i = i.split('gzip ')[1]
1915
+ end
1916
+ # ======================================================================== #
1917
+ # === Handle groff next:
1918
+ # ======================================================================== #
1919
+ if i.include? 'groff '
1920
+ i = i.split('groff ')[1]
1921
+ if i.include? 'version'
1922
+ i = i.split('version').last.strip
1923
+ end
1924
+ end
1925
+ # ======================================================================== #
1926
+ # === Handle ethtool next:
1927
+ # ======================================================================== #
1928
+ if i.include? 'ethtool '
1929
+ i = i.split('ethtool ')[1]
1930
+ end
1931
+ # ======================================================================== #
1932
+ # === Handle tmux next:
1933
+ # ======================================================================== #
1934
+ if i.include? 'tmux '
1935
+ i = i.split('tmux').last.strip
1936
+ end
1937
+ # ======================================================================== #
1938
+ # === Handle sysstag next:
1939
+ # ======================================================================== #
1940
+ if i.include? 'sysstat version '
1941
+ i = i.split('sysstat version').last.to_s.strip
1942
+ end
1943
+ # ======================================================================== #
1944
+ # === Handle samtools next:
1945
+ # ======================================================================== #
1946
+ if i.include? 'samtools '
1947
+ i = i.split('samtools ').last.to_s.strip
1948
+ end
1949
+ # ======================================================================== #
1950
+ # === Handle the Linux kernel next
1951
+ # ======================================================================== #
1952
+ if i.start_with?('Linux ')
1953
+ i = i.scan(
1954
+ /(\d{1,2}\.\d{1,2}\.\d{1,2})/
1955
+ ).flatten.first.to_s
1956
+ end
1957
+ # ======================================================================== #
1958
+ # === Handle the xz-utils next:
1959
+ # ======================================================================== #
1960
+ if i.include? 'xz (XZ Utils)'
1961
+ i = i.split('xz (XZ Utils)').last
1962
+ end
1963
+ # ======================================================================== #
1964
+ # === Handle xterm next:
1965
+ # ======================================================================== #
1966
+ if i.include? 'XTerm('
1967
+ i = i.split('XTerm(').last.delete(')')
1968
+ end
1969
+ # ======================================================================== #
1970
+ # === Handle gnuplot:
1971
+ # ======================================================================== #
1972
+ if i.include? ' patchlevel'
1973
+ i = i.split('patchlevel').first
1974
+ end
1975
+ # ======================================================================== #
1976
+ # === Handle patch next:
1977
+ # ======================================================================== #
1978
+ if i.include? 'GNU patch '
1979
+ i = i.split('GNU patch ').last
1980
+ end
1981
+ # ======================================================================== #
1982
+ # === Handle simple-scan:
1983
+ # ======================================================================== #
1984
+ if i.include? 'simple-scan '
1985
+ i = i.split('simple-scan').last
1986
+ end
1987
+ # ======================================================================== #
1988
+ # === Handle ffmpeg next:
1989
+ # ======================================================================== #
1990
+ if i.include? 'ffmpeg version'
1991
+ # ffmpeg version N-114276-g7f4b8d2f5e Copyright (c) 2000-2024 the FFmpeg developers
1992
+ i = i.scan(/ffmpeg version (.+) /).flatten.first.to_s
1993
+ i = i.split(' ').first if i.include? ' '
1994
+ if i.include? '-'
1995
+ i = i.scan(
1996
+ /-(\d{5,6})-/
1997
+ ).flatten.first.to_s
1998
+ end
1999
+ end
2000
+ # ======================================================================== #
2001
+ # === Handle GCC next:
2002
+ #
2003
+ # The String we are looking for is like:
2004
+ #
2005
+ # "gcc version: 14.0.1 20240326 (experimental)"
2006
+ #
2007
+ # ======================================================================== #
2008
+ if i.include?('gcc (GCC)') or i.include?('gcc version')
2009
+ first_line = i.split("\n").first
2010
+ i = first_line.split('gcc (GCC) ').last.strip
2011
+ if i.include? ' '
2012
+ i = i.split(' ').first
2013
+ end
2014
+ end
2015
+ # ======================================================================== #
2016
+ # === Handle Lynx next
2017
+ # ======================================================================== #
2018
+ if i.include? 'Lynx Version ' # Lynx Version 2.9.0 (15 Jan 2024)
2019
+ i = i.scan(
2020
+ /Lynx Version (\d{1,2}\.\d{1,2}\.\d{1,2})/
2021
+ ).flatten.first.to_s
2022
+ end
2023
+ # ======================================================================== #
2024
+ # === openjdk
2025
+ # ======================================================================== #
2026
+ if i.include? 'openjdk'
2027
+ i = i.scan(/openjdk version "(\d{1,2}\.\d{1,2}\.\d{1,2})"/).flatten.first
2028
+ end
2029
+ # ======================================================================== #
2030
+ # if i.include? 'GNOME Document Viewer'
2031
+ # i.sub!(/GNOME Document Viewer/,'') # For evince specifically.
2032
+ # end
2033
+ # ======================================================================== #
2034
+ if i.include? 'GNU'
2035
+ i.gsub!(/GNU/,'')
2036
+ end
2037
+ # ======================================================================== #
2038
+ # === Handle ruby 'ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]'
2039
+ # ======================================================================== #
2040
+ if i.include? 'ruby '
2041
+ i = i.scan(
2042
+ /^ruby (\d{1,1}\.\d{1,1}\.\d{1,1})/
2043
+ ).flatten.first.to_s
2044
+ end
2045
+ # ======================================================================== #
2046
+ # === Handle 'ncurses 6.2.20200212' aka ncurses
2047
+ # ======================================================================== #
2048
+ if i.include? 'ncurses '
2049
+ i = i.scan(
2050
+ /ncurses (\d{1,1}\.\d{1,1})/
2051
+ ).flatten.first.to_s
2052
+ end
2053
+ # ======================================================================== #
2054
+ # === Handle Imagemagick: 'Version: ImageMagick 7.0.10-28'
2055
+ # ======================================================================== #
2056
+ if i.include? 'Version: ImageMagick '
2057
+ i = i.scan(
2058
+ /Version: ImageMagick (\d{0,2}\.\d{0,2}\.\d{0,2}-\d{0,2})/
2059
+ ).flatten.first.to_s.tr('-','.')
2060
+ end
2061
+ # ======================================================================== #
2062
+ # === Handle Qt next:
2063
+ # ======================================================================== #
2064
+ if i.include? 'uic ' # uic 5.15.12
2065
+ i = i.split('uic ').last
2066
+ elsif i.include? 'Using Qt version' # Using Qt version 6.6.3 in
2067
+ i = i.scan(
2068
+ /Using Qt version (\d{1,2}\.\d{1,2}\.\d{1,2})/
2069
+ ).flatten.first
2070
+ end
2071
+ # ======================================================================== #
2072
+ # === Handle perl next:
2073
+ # ======================================================================== #
2074
+ if i.include?('This is perl') and i.include?('(v') # "This is perl 5, version 38, subversion 2 (v5.38.2) built for x86_64-linux",
2075
+ # ====================================================================== #
2076
+ # Alternatively we could use this regex:
2077
+ #
2078
+ # /\(v(\d{0,2}\.?\d{0,2}\.\d{0,2})\)/
2079
+ #
2080
+ # ====================================================================== #
2081
+ i = i.scan(
2082
+ /\((v\d{1,2}\.\d{1,2}\.\d{1,2})\)/
2083
+ ).flatten.first.to_s.dup
2084
+ end
2085
+ # ======================================================================== #
2086
+ # === Handle awk next:
2087
+ # ======================================================================== #
2088
+ if i.include? 'Awk '
2089
+ i = i.scan(/Awk (\d{1,2}\.\d{1,2}\.\d{1,2})/).flatten.first
2090
+ end
2091
+ # ======================================================================== #
2092
+ # === Handle patchelf '0.12.20200827.8d3a16e'
2093
+ #
2094
+ # This can also include output such as "patchelf 0.14.3".
2095
+ # ======================================================================== #
2096
+ if i.include? 'patchelf '
2097
+ i = i.scan(
2098
+ /^patchelf (\d{1,1}\.\d{1,2}\.?\d{0,2})/
2099
+ ).flatten.first.to_s
2100
+ end
2101
+ # ======================================================================== #
2102
+ # === Work on NASM next:
2103
+ # ======================================================================== #
2104
+ if i.include? 'NASM ' # "NASM version 2.16.01 compiled on Mar 23 2024"
2105
+ scanned = i.scan(
2106
+ /NASM\s*version\s*(\d{1,2}\.\d{1,2}\.\d{1,2})/
2107
+ )
2108
+ i = scanned.flatten.first.to_s.strip
2109
+ end
2110
+ # ======================================================================== #
2111
+ # === Handle bzip2 next:
2112
+ # ======================================================================== #
2113
+ if i.include? 'bzip2, a block'
2114
+ i = i.scan(
2115
+ /Version (\d{1,2}\.\d{1,2}\.\d{1,2}),/
2116
+ ).flatten.first.to_s
2117
+ end
2118
+ # ======================================================================== #
2119
+ # === Handle emacs next:
2120
+ # ======================================================================== #
2121
+ if i.include? 'Emacs '
2122
+ i.sub!(/Emacs/,'')
2123
+ end
2124
+ # ======================================================================== #
2125
+ # === bzip2recover
2126
+ # ======================================================================== #
2127
+ if i.include? 'extracts blocks from damag'
2128
+ i = i.scan(
2129
+ /bzip2recover (\d{0,2}\.\d{0,2}\.\d{0,2}): extracts blocks from damaged .bz2 files/
2130
+ ).flatten.first.to_s.dup
2131
+ end
2132
+ # ======================================================================== #
2133
+ # === Handle Python next:
2134
+ # ======================================================================== #
2135
+ if i.include? 'Python ' # Python 3.11.7
2136
+ i.sub!(/Python /,'')
2137
+ end
2138
+ # ======================================================================== #
2139
+ # === Remove "built on linux-gnu":
2140
+ # ======================================================================== #
2141
+ if i.include? ' built on linux-gnu.'
2142
+ i.gsub!(/ built on linux-gnu\./, '') # Fixing wget specifically.
2143
+ end
2144
+ # ======================================================================== #
2145
+ # === Remove 'Wget' substring:
2146
+ # ======================================================================== #
2147
+ if i.include? 'Wget'
2148
+ i.sub!(/Wget/,'')
2149
+ i.strip!
2150
+ end
2151
+ if i.include? 'built on'
2152
+ i = i.split(/built on/).first
2153
+ end
2154
+ # ======================================================================== #
2155
+ # === Handle "Midnight Commander" next:
2156
+ # ======================================================================== #
2157
+ if i.include? 'Midnight Commander'
2158
+ i.gsub!(/Midnight Commander/, '')
2159
+ end
2160
+ # ======================================================================== #
2161
+ # === Eliminate '.git'
2162
+ # ======================================================================== #
2163
+ if i.include? '.git'
2164
+ i.sub!(/\.git/,'')
2165
+ end
2166
+ # ======================================================================== #
2167
+ # === Remove the substring 'GNU' next; this should come fairly late:
2168
+ # ======================================================================== #
2169
+ if i.include? 'GNU'
2170
+ i.sub!(/GNU/,'')
2171
+ end
2172
+ # ======================================================================== #
2173
+ # === For rsync specifically
2174
+ # ======================================================================== #
2175
+ if i.include? 'protocol version'
2176
+ i = i.split('protocol version').first
2177
+ end
2178
+ # ======================================================================== #
2179
+ # === Remove '#'
2180
+ # ======================================================================== #
2181
+ if i.include? ' #' # Handle "uname -a" aka Linux darkstar.example.net 5.4.50 #1 SMP
2182
+ i = i.split(' #').first.strip
2183
+ end
2184
+ if i.start_with? 'v'
2185
+ i = i.dup
2186
+ i[0,1] = ''
2187
+ end
2188
+ return i
2189
+ end; self.instance_eval { alias sanitize_this_program_version sanitize_this_version_string } # === EnvironmentInformation.sanitize_this_program_version
2190
+
2191
+ # ========================================================================== #
2192
+ # === EnvironmentInformation.return_very_silent_system_output_from (query tag)
2193
+ # ========================================================================== #
2194
+ def self.return_very_silent_system_output_from(
2195
+ use_this_query
2196
+ )
2197
+ @original_stderr = $stderr.clone
2198
+ $stderr.reopen('/dev/null', 'w')
2199
+ result = `#{use_this_query} 2>&1`
2200
+ $stderr.reopen(@original_stderr)
2201
+ return result
2202
+ end; self.instance_eval { alias silent_sys_command return_very_silent_system_output_from } # === EnvironmentInformation.silent_sys_command
2203
+ self.instance_eval { alias default_query return_very_silent_system_output_from } # === EnvironmentInformation.default_query
2204
+ self.instance_eval { alias silent_query return_very_silent_system_output_from } # === EnvironmentInformation.silent_query
2205
+
2206
+ end
2207
+
2208
+ if __FILE__ == $PROGRAM_NAME
2209
+ alias e puts
2210
+ # e EnvironmentInformation.n_subcommands?.to_s+' components are tracked.'
2211
+ # e EnvironmentInformation.internet_is_available?
2212
+ # EnvironmentInformation.e('Hello world!')
2213
+ # e EnvironmentInformation.return_remote_gtk2_version
2214
+ # EnvironmentInformation.write_what_into(ARGV, 'test_this.md')
2215
+ # Next test .simple_version()
2216
+ seek_this_program = :bison # :gnuplot # :lftp
2217
+ _ = EnvironmentInformation.return_version_of(seek_this_program)
2218
+ e _
2219
+ # ========================================================================== #
2220
+ # Next we test various individual components, stored in an Array:
2221
+ # ========================================================================== #
2222
+ array = %i(
2223
+ mpc
2224
+ gtk2
2225
+ linux
2226
+ binutils
2227
+ boost
2228
+ coreutils
2229
+ diffutils
2230
+ ffmpeg
2231
+ findutils
2232
+ java
2233
+ imagemagick
2234
+ kde_frameworks
2235
+ llvm
2236
+ ncurses
2237
+ nginx
2238
+ qt
2239
+ rubygems
2240
+ sharutils
2241
+ sysstat
2242
+ swig
2243
+ texinfo
2244
+ tmux
2245
+ xfsprogs
2246
+ xterm
2247
+ hmmer
2248
+ viennarna
2249
+ xstdcmap
2250
+ )
2251
+ array.each {|entry|
2252
+ _ = EnvironmentInformation.version_of(entry)
2253
+ e _
2254
+ }
2255
+ e EnvironmentInformation.return_version_of_mpc
2256
+ e EnvironmentInformation.return_version_of_boost
2257
+ EnvironmentInformation.test
2258
+ end # showcomponents --compare