Module: RBT::Action::SoftwareManager::Deprecated

Defined in:
lib/rbt/actions/individual_actions/software_manager/deprecated.rb

Instance Method Summary collapse

Instance Method Details

#a_problem_has_occurredObject

#

a_problem_has_occurred

This method simply denotes that a problem has occurred. It is not more specific than that.

#


448
449
450
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 448

def a_problem_has_occurred
  @internal_hash[:problem] = true
end

#an_error_has_occurredObject

#

an_error_has_occurred

This is a setter-method.

#


720
721
722
723
724
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 720

def an_error_has_occurred
  we_can_not_continue_and_we_will_not_run_make_install
  @internal_hash[:an_error_has_occurred] = true
  the_program_has_failed_to_install
end

#check_for_common_errorsObject

#

check_for_common_errors

This mehod can be used to check (and handle) errors that we have encountered.

#


344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 344

def check_for_common_errors
  _ = errors?
  if _.is_a? Array
    _.each {|entry|
      case entry
      # =================================================================== #
      # === :gir_file_could_not_be_found
      # =================================================================== #
      when :gir_file_could_not_be_found
        opne 'A required package could not be found, related '\
             'to .gir (gobject introspection) files.'
        error_is(:required_package_was_not_found)
      # =================================================================== #
      # === :required_package_was_not_found
      # =================================================================== #
      when :required_package_was_not_found
        error_is(:required_package_was_not_found)
      # =================================================================== #
      # === :ninja_build_encountered_an_error
      # =================================================================== #
      when :ninja_build_encountered_an_error
        error_is(:ninja_build_encountered_an_error)
      # =================================================================== #
      # === :configure_error
      #
      # This error occurs when configure failed for some reason. It is
      # a somewhat generic error and may occur, for example, when a
      # certain package is missing.
      #
      # Example for this:
      #
      #   No package 'libmate-menu' found
      #
      # =================================================================== #
      when :configure_error
        opnerror 'Some configure-related error has occurred.'
      # =================================================================== #
      # === Python syntax error: Invalid Syntax
      # =================================================================== #
      when :python_syntax_error_invalid_syntax
        opnerror 'This InvalidSyntax error is often related to the different'
        opnerror 'syntax that python2 and python3 use.'
        # ================================================================= #
        # Consider autoswitching the python-version next:
        # ================================================================= #
        if is_on_roebe?
          if autoswitch_python?
            opne "#{rev}The configuration file "\
                 "#{slateblue('autoswitch_python.yml')}"\
                 " #{rev}has been set to true."
            opne "#{rev}We will consider switching python "\
                 "next (to #{slateblue('python')})#{rev}."
            result_of_enabling_python2 = enable_python2
            if result_of_enabling_python2 == true
              clear_errors
              do_compile_this_program(
                compile_which_program?
              )
            end
          else
            # ============================================================= #
            # In this case, notify the user that autoswitching could
            # be enabled. This clause here is entered when autoswitching
            # has been disabled.
            # ============================================================= #
            opne 'Do note that you could set the autoswitch-python '\
                 'variable to true.'
            opne "This could be done by modifying the content "\
                 "of the file #{slateblue('autoswitch_python.yml')}."
            opne 'Having autoswitch-python enabled may, however had, '\
                 'also lead to problems sometimes, so'
            opne 'make sure that you really want to enable this '\
                 'functionality, prior to changing that file.'
          end
        end
      # =================================================================== #
      # === A general make-related error
      # =================================================================== #
      when :make_encountered_some_error
        # ================================================================= #
        # This error type is too generic for now - but perhaps in the
        # future we may also handle it somehow, or give the user
        # more information about it.
        # ================================================================= #
      else
        # ================================================================= #
        # For now this "debugging" part only occurs on roebe-systems.
        # ================================================================= #
        if is_on_roebe?
          opnn
          stderr "Unregistered error: #{slateblue(entry)} "\
                 "#{rev}(class: #{lightblue(entry.class.to_s)})"
        end
      end
    }
  end
end

#check_for_common_problemsObject Also known as: try_to_report_the_problem, check_for_problems_again

#

check_for_common_problems (problems tag, problem tag)

This method will check for some problems and offer ways to resolve these issues. For this to work, the particular problem at hand has to be registered in the following case/when menu.

This method is for checking problems - but for the time being (Nov 2018) we will also check for common errors within this method. This is perhaps not ideal, but simplifies the code for now. In the future this may have to be changed (or the method may have to be renamed).

#


527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 527

def check_for_common_problems
  _ = problems?
  if _
    # ===================================================================== #
    # We will only handle registered Symbols next.
    # ===================================================================== #
    if _.is_a? Symbol
      case _ # case tag
      # =================================================================== #
      # === Libtool could not find the library
      # =================================================================== #
      when :libtool_could_not_find_the_library
        if is_on_roebe?
          unless @internal_hash[:invalid_libtool_archive].nil?
            line = @internal_hash[:invalid_libtool_archive]
            try_to_autocorrect_this_erroneous_libtool_entry(line)
          end
        end
      # =================================================================== #
      # === Encountered an invalid libtool archive
      # =================================================================== #
      when :encountered_an_invalid_libtool_archive
        if is_on_roebe?
          unless @internal_hash[:invalid_libtool_archive].nil?
            line = @internal_hash[:invalid_libtool_archive]
            try_to_autocorrect_this_erroneous_libtool_entry(line)
          end
        end
      # =================================================================== #
      # === Libtool can not install to another prefix
      # =================================================================== #
      when :libtool_can_not_install_to_another_prefix
        opne 'Libtool apparently can not install to another prefix.'
        opne 'The main reason for this is usually that the configure script'
        opne 'was run from a directory before, but with another --prefix.'
        opne 'Try to run "make clean" in the base directory or remove the'
        opne 'extracted archive, in order to try to fix this problem.'
        if is_on_roebe?
          opne tomato('Removing')+' the extracted archive next.'
          remove_the_extracted_archive
        end
      # =================================================================== #
      # === missing_header_ladspa
      # =================================================================== #
      when :missing_header_ladspa
        opne 'The header ladspa.h is missing. This is part of the '\
             'ladspa-sdk package.'
        orev 'The remote URL should be at: '+
              sfancy(return_url_for(:ladspa))
        e
        e 'This program can probably be installed via:'
        e
        e "  #{sfancy('rbt ladspa')}"
        e
      # =================================================================== #
      # === Incomplete configure error via cmake
      #
      # This entry point is for cmake-related errors that are not further
      # specified - in other words, generic cmake-related errors.
      # =================================================================== #
      when :incomplete_configure_error_via_cmake
        do_skip_postinstall_actions
        opne "Something went wrong via `#{powderblue('cmake')}`."
      # =================================================================== #
      # === The totem playlist was not found
      # =================================================================== #
      when :totem_playlist_was_not_found
        opne 'The totem playlist was not found. You can try '\
             'to compile it:'
        e
        opne sfancy('  rbt totem-playlist')
        e
      # =================================================================== #
      # === Missing C .h (header) file
      # =================================================================== #
      when :missing_c_header_file
        opne swarn('An important C .h file is missing - the compilation '\
             'can not proceed.')
        # ================================================================= #
        # The next line was added on 22.08.2018. I wanted to make sure to
        # easily look at the error for programs that have failed, like
        # this program here.
        # ================================================================= #
        do_not_remove_extracted_archive
        which_h_file = sys_command_string?.select {|inner_line|
          inner_line.include?('fatal error:') and
          inner_line.include?('No such file or directory')
        }
        use_this_regex = /fatal error. (.+\.h):/
        which_h_file.first =~ use_this_regex
        this_file = $1.to_s.dup
        case this_file
        # ================================================================= #
        # === xf86Resources.h
        # ================================================================= #
        when 'xf86Resources.h'
          opne "The file #{sfile(this_file)} belongs to the very old package"
          opne 'xf86-video-amd-2.7.7.7.tar.xz. This has not been updated since'
          opne '2008 so things will most likely no longer compile.'
        end
      # =================================================================== #
      # === Python import error: an undefined symbol
      #
      # Note that this is a problem, not necessarily an error.
      # =================================================================== #
      when :python_import_error_undefined_symbol
        opne 'A python '+swarn('ImportError')+' has happened, about '\
             'a missing/undefined Symbol.'
        if sys_command_string?.any? {|inner_line|
            inner_line.include? 'lib/gobject-introspection'
          }
          opne 'The problem appears to be somehow related to gobject-introspection.'
          opne 'This error may appear when different python versions or '
          opne 'different library locations are used at the same time.'
        end
      # =================================================================== #
      # === Docbook failed to load a network entity
      #
      # This entry point is related to docbook.
      # =================================================================== #
      when :docbook_failed_to_load_a_network_entity
        opne "Docbook failed to load a "\
             "#{steelblue('(remote) network entity')}."
        opne 'In theory, this could be resolved by installing the docbook'
        opne 'stack, but this is not necessarily trivial. Have a look at the'
        opne 'LFS page for now:'
        e
        result = action(:return_blfs_entry_for, 'docbook')
        e "  #{sfancy(result)}"
        e
      # =================================================================== #
      # === No configure file
      # =================================================================== #
      when :no_configure_file
        opnn; _ = "No #{sfancy('configure')}#{rev} file was found."
      # =================================================================== #
      # === Jam is missing
      # =================================================================== #
      when :jam_is_missing
        do_skip_postinstall_actions
        notify_the_user_that_this_program_is_missing(:jam)
      # =================================================================== #
      # === Meson could not be found
      # =================================================================== #
      when :meson_could_not_be_found
        do_skip_postinstall_actions
        notify_the_user_that_this_program_is_missing(:meson) {
          e orange(
              'Note that this will require a recent python 3.x '\
              'version on your host system.'
            )
          e orange(
              'Additionally, you may need the build tool called '\
              'ninja:'
            )
          e
          e '  '+sfancy('rbt ninja')
          e
        }
      end
    elsif _.is_a? Array
      _ = problem?
      first = _.first
      last  = _.last
      last  = last.first if last.is_a? Array
      case first # case tag
      # =================================================================== #
      # === python_import_error_missing_module
      # =================================================================== #
      when :python_import_error_missing_module
        orev "The python module `#{sfancy(last)}#{rev}` is missing."
        case last
        # ================================================================= #
        # === libxml2
        # ================================================================= #
        when /libxml2?/
          orev "You may be able to resolve this problem, by "\
               "#{steelblue('compiling libxml2')}#{rev}:"
          e
          orev "  #{sfancy('rbt libxml2')}"
          e
        end
      end
    end
  end
end

#check_for_common_problems_and_common_errorsObject

#

check_for_common_problems_and_common_errors

#


63
64
65
66
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 63

def check_for_common_problems_and_common_errors
  check_for_common_problems
  check_for_common_errors
end

#check_for_errors?Boolean Also known as: honour_error_results?

#

check_for_errors?

#

Returns:

  • (Boolean)


49
50
51
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 49

def check_for_errors?
  !ignore_errors?
end

#clear_errorsObject

#

clear_errors

#


462
463
464
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 462

def clear_errors
  RBT.clear_errors
end

#clear_problemsObject

#

clear_problems

Reset the problems, so that we don’t have any problems.

#


137
138
139
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 137

def clear_problems
  problem_is :no_problem
end

#do_ignore_errorsObject Also known as: do_ignore_the_errors

#

do_ignore_errors

#


192
193
194
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 192

def do_ignore_errors
  @internal_hash[:ignore_errors] = true
end

#error_is(this_error = :meson_could_not_be_found) ⇒ Object

#

error_is (error_is tag)

This registered an error. An error is always a problem, but some problems allow us to continue the installation steps. An error on the other hand will end the installation procedure.

#


162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 162

def error_is(
    this_error = :meson_could_not_be_found
  )
  problem_is(this_error)
  an_error_has_occurred
  # ======================================================================= #
  # Register the error on the main RBT namespace as well.
  # ======================================================================= #
  RBT.append_error_message(
    this_error
  )
end

#error_message?Boolean Also known as: error_is?

#

error_message?

#

Returns:

  • (Boolean)


185
186
187
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 185

def error_message?
  RBT.error_message?
end

#errors?Boolean

#

errors?

#

Returns:

  • (Boolean)


334
335
336
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 334

def errors?
  RBT::Errors::MapLineToASpecificError.registered_errors?.uniq
end

#has_a_problem_occurred?Boolean Also known as: a_problem_has_occurred?

#

has_a_problem_occurred?

Query-method over as to whether a problem has occurred or whether it has not.

#

Returns:

  • (Boolean)


320
321
322
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 320

def has_a_problem_occurred?
  problem?
end

#ignore_errors?Boolean Also known as: ignore_errors_anyway?

#

ignore_errors?

This query-method allows the user to ignore errors.

#

Returns:

  • (Boolean)


213
214
215
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 213

def ignore_errors?
  @internal_hash[:ignore_errors]
end

#missing_packages?Boolean

#

missing_packages?

#

Returns:

  • (Boolean)


327
328
329
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 327

def missing_packages?
  RBT::Errors::MapLineToASpecificError.missing_packages?
end

#no_error_has_occurred?Boolean

#

no_error_has_occurred?

#

Returns:

  • (Boolean)


178
179
180
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 178

def no_error_has_occurred?
  !an_error_has_occurred?
end

#no_error_was_encountered?Boolean Also known as: has_been_installed_successfully?

#

no_error_was_encountered?

#

Returns:

  • (Boolean)


56
57
58
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 56

def no_error_was_encountered?
  !an_error_has_occurred?
end

#no_problem_has_occurred?Boolean Also known as: no_problem_was_encountered?

#

no_problem_has_occurred?

This method will return true if no problem has occurred - otherwise it will return false.

#

Returns:

  • (Boolean)


310
311
312
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 310

def no_problem_has_occurred?
  !problem?
end

#problem?Boolean Also known as: problems?, problem_is?, registered_errors?

#

problem?

#

Returns:

  • (Boolean)


71
72
73
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 71

def problem?
  @internal_hash[:problem]
end

#problem_is(i = nil, optional_extra_information = nil) ⇒ Object

#

problem_is

Keep in mind that not every problem is an error. An error will indicate that copilationg will (or already has) fail(ed).

An example for an error may be :missing_headers, which indicates that some .h files may be missing (or could not be found, anyway).

An example for a problem may be some add-on failing, without this being a “critical problem” (aka an error).

This file here holds code, as part of RBT::Action::SoftwareManager, which handles specific “problems”, in particular during GNU configure invocations, and more serious problems, also called “errors” (aka “critical problems”).

Now - what does this effectively mean?

For instance, consider that the configure script determines that you are missing some .h header file or some linking step can not be done. Then the user should be notified about this problem in a constructive, useful manner as well - or at the least be able to do so. This information should be helpful, and ideally provide suggestions as to how to resolve the issue at hand.

The GNU configure scripts are often extremely cryptic to a user, so this code here also attempts to make it easier to discover what kind of problems are giving issues. Some errors such as faulty libtool files, can sometimes be automatically corrected, to some extent (that is, remove or correct the faulty libtool file, and then continue).

For each of the “triumvirate” of compiling, that is “configure”, “make” and “make install” steps, we can set success or failure individually.

#


113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 113

def problem_is(
    i                          = nil,
    optional_extra_information = nil
  )
  case i
  when :default,
       :no_problem # This is the default too. The nil value will be used in these cases.
    i = nil
  end
  if i.is_a? Array
    i = i.first # Only use the first Array entry.
  end
  if optional_extra_information
    @internal_hash[:problem] = [i, optional_extra_information]
  else # This here is the default - it is a LOT more common.
    @internal_hash[:problem] = i
  end
end

#registered_erroneous_libtool_entries?Boolean Also known as: erroneous_libtool_entries?

#

registered_erroneous_libtool_entries?

#

Returns:

  • (Boolean)


455
456
457
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 455

def registered_erroneous_libtool_entries?
  RBT::Errors::MapLineToASpecificError.erroneous_libtool_entries?
end

#reset_error_map_line_to_a_specific_errorObject

#

reset_error_map_line_to_a_specific_error

#


151
152
153
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 151

def reset_error_map_line_to_a_specific_error
  RBT::Errors::MapLineToASpecificError.clear
end

#run_through_the_behaviour_changesObject

#

run_through_the_behaviour_changes

We run through the module that keeps track of the behaviour changes that out to be run in class RBT::Action::SoftwareManager.

#


202
203
204
205
206
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 202

def run_through_the_behaviour_changes
  RBT::Errors::MapLineToASpecificError.behaviour_changes?.each {|do_this_action|
    self.send(do_this_action)
  }
end

#run_through_the_registered_errorsObject

#

run_through_the_registered_errors

Sync the errors towards class RBT::Action::SoftwareManager next.

#


498
499
500
501
502
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 498

def run_through_the_registered_errors
  RBT::Errors::MapLineToASpecificError.registered_errors?.each {|do_this_action|
    error_is do_this_action
  }
end

#run_through_the_registered_problemsObject

#

run_through_the_registered_problems

Sync the problems towards class RBT::Action::SoftwareManager next.

#


228
229
230
231
232
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 228

def run_through_the_registered_problems
  RBT::Errors::MapLineToASpecificError.registered_problems?.each {|do_this_action|
    problem_is do_this_action
  }
end

#run_through_the_registered_problems_registered_errors_and_behaviour_changesObject

#

run_through_the_registered_problems_registered_errors_and_behaviour_changes

#


507
508
509
510
511
512
513
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 507

def run_through_the_registered_problems_registered_errors_and_behaviour_changes
  run_through_the_registered_problems
  run_through_the_registered_errors
  run_through_the_behaviour_changes
  run_through_the_erroneous_libtool_entries
  run_through_the_required_dependencies
end

#run_through_the_required_dependenciesObject

#

run_through_the_required_dependencies

We have to sync the dependencies back into class RBT::Action::SoftwareManager.

#


239
240
241
242
243
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 239

def run_through_the_required_dependencies
  RBT::Errors::MapLineToASpecificError.required_dependency?.each {|this_array|
    register_required_dependency(this_array.first, this_array.last)
  }
end

#stop_on_error(be_verbose = true) ⇒ Object

#

stop_on_error

Method call to stop if the user wanted to.

#


481
482
483
484
485
486
487
488
489
490
491
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 481

def stop_on_error(
    be_verbose = true
  )
  if be_verbose
    stderr return_opnn, :use_print
    stderr 'We will exit now because this behaviour is enabled'
    stderr return_opnn, :use_print
    stderr "#{rev}in the configuration file (the entry: #{teal('stop_on_error')})#{rev}."
  end
  exit_program if stop_on_error?
end

#the_program_has_failed_to_installObject

#

the_program_has_failed_to_install

#


144
145
146
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 144

def the_program_has_failed_to_install
  @internal_hash[:has_the_program_been_installed_successfully] = false
end

#try_to_give_additional_information_to_the_user_if_the_missing_header_is_registeredObject

#

try_to_give_additional_information_to_the_user_if_the_missing_header_is_registered

#


248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'lib/rbt/actions/individual_actions/software_manager/deprecated.rb', line 248

def try_to_give_additional_information_to_the_user_if_the_missing_header_is_registered
  # ======================================================================= #
  # First obtain all errors next:
  # ======================================================================= #
  _ = RBT::Errors::MapLineToASpecificError.all_programs_and_errors?.flatten
  unless _.empty?
    # ===================================================================== #
    # We must scan for errors such as:
    #
    #   ../deps/uvwasi/src/fd_table.c:9:10: fatal error: uv.h: No such file or directory
    #
    # ===================================================================== #
    selection = _.select {|line|
      line.is_a?(String) and
      line.include?('fatal error: ') and
      line.include?('No such file or directory')
    }.uniq
    regex_to_use = / ([A-Za-z]+\.h): /
    scanned = selection.first
    this_header_file_is_missing = nil
    if scanned
      scanned = scanned.scan(regex_to_use)
      this_header_file_is_missing = scanned.flatten.first
    end
    if this_header_file_is_missing
      this_header_file_is_missing.strip!
      # =================================================================== #
      # Now that we have the header file, we will check whether this
      # .h is registered in the RBT "database". 
      # =================================================================== #
      if RBT.is_this_partial_header_included?(this_header_file_is_missing)
        match = RBT::Cookbooks.all_headers?.select {|key, value|
          # =============================================================== #
          # Next, we must include the leading / to distinguish between
          # "libuv.yml: - uv.h" and "freerdp.yml: - freerdp2/freerdp/codec/yuv.h"
          # Without the '/' the latter would also be included as a potential
          # match.
          # =============================================================== #
          key.include?(this_header_file_is_missing) and
          !(key =~ /\/[A-Za-z]+#{this_header_file_is_missing}$/)
         }
        if match and !match.empty?
          orev "The .h header file #{steelblue(this_header_file_is_missing)} "\
               "is currently not installed"
          orev "on this system, but it is available as part of the"
          orev "project #{lightblue(match.values.first)}#{rev}."
          orev "#{tomato('You could consider compiling it via:')}"
          e
          e '  '+lightgreen("rbt #{match.values.first}")
          e
        end
      end
    end
  end
end