This file is indexed.

/usr/lib/ruby/vendor_ruby/octocatalog-diff/catalog-diff/display.rb is in octocatalog-diff 1.5.3-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# frozen_string_literal: true

require_relative '../api/v1/diff'
require_relative 'differ'
require_relative 'display/json'
require_relative 'display/legacy_json'
require_relative 'display/text'

module OctocatalogDiff
  module CatalogDiff
    # Prepare a display of the results from a catalog-diff. Intended that this will contain utility
    # methods but call out to a OctocatalogDiff::CatalogDiff::Display::<something> class to display in
    # the desired format.
    class Display
      # Display the diff in some specified format.
      # @param diff_in [OctocatalogDiff::CatalogDiff::Differ | Array<Diff results>] Diff to display
      # @param options [Hash] Consisting of:
      #          - :header [String] => Header (can be :default to construct header)
      #          - :display_source_file_line [Boolean] => Display manifest filename and line number where declared
      #          - :compilation_from_dir [String] => Directory where 'from' catalog was compiled
      #          - :compilation_to_dir [String] => Directory where 'to' catalog was compiled
      #          - :display_detail_add [Boolean] => Set true to display parameters of newly added resources
      # @param logger [Logger] Logger object
      # @return [String] Text output for provided diff
      def self.output(diff_in, options = {}, logger = nil)
        diff_x = diff_in.is_a?(OctocatalogDiff::CatalogDiff::Differ) ? diff_in.diff : diff_in
        raise ArgumentError, "text_output requires Array<Diff results>; passed in #{diff_in.class}" unless diff_x.is_a?(Array)
        diff = diff_x.map { |x| OctocatalogDiff::API::V1::Diff.factory(x) }

        # req_format means 'requested format' because 'format' has a built-in meaning to Ruby
        req_format = options.fetch(:format, :color_text)

        # Options hash to pass to display method
        opts = {}
        opts[:header] = header(options)
        opts[:display_source_file_line] = options.fetch(:display_source_file_line, false)
        opts[:compilation_from_dir] = options[:compilation_from_dir] || nil
        opts[:compilation_to_dir] = options[:compilation_to_dir] || nil
        opts[:display_detail_add] = options.fetch(:display_detail_add, false)
        opts[:truncate_details] = options.fetch(:truncate_details, true)
        opts[:display_datatype_changes] = options.fetch(:display_datatype_changes, false)

        # Call appropriate display method
        case req_format
        when :json
          logger.debug 'Generating JSON output' if logger
          OctocatalogDiff::CatalogDiff::Display::Json.generate(diff, opts, logger)
        when :legacy_json
          logger.debug 'Generating Legacy JSON output' if logger
          OctocatalogDiff::CatalogDiff::Display::LegacyJson.generate(diff, opts, logger)
        when :text
          logger.debug 'Generating non-colored text output' if logger
          OctocatalogDiff::CatalogDiff::Display::Text.generate(diff, opts.merge(color: false), logger)
        when :color_text
          logger.debug 'Generating colored text output' if logger
          OctocatalogDiff::CatalogDiff::Display::Text.generate(diff, opts.merge(color: true), logger)
        else
          raise ArgumentError, "Unrecognized text format '#{req_format}'"
        end
      end

      # Utility method!
      # Construct the header for diffs
      # Default is diff <old_branch_name>/<node_name> <new_branch_name>/<node_name>
      # @param opts [Hash] Options hash from CLI
      # @return [String] Header in indicated format
      def self.header(opts)
        return nil if opts[:no_header]
        return opts[:header] unless opts[:header] == :default
        node = opts.fetch(:node, 'node')
        from_br = opts.fetch(:from_env, 'a')
        to_br = opts.fetch(:to_env, 'b')
        from_br = 'current' if from_br == '.'
        to_br = 'current' if to_br == '.'
        "diff #{from_br}/#{node} #{to_br}/#{node}"
      end

      # Utility method!
      # Go through the 'diff' array, filtering out ignored items and classifying each change
      # as an addition (+), subtraction (-), change (~), or nested change (!). This creates
      # hashes for each type of change that are consumed later for ordering purposes.
      # @param diff [Array<Diff results>] The diff which *must* be in this format
      # @return [Array<Hash of adds, Hash of removes, Hash of changes, Hash of nested] Processed results
      def self.parse_diff_array_into_categorized_hashes(diff)
        only_in_old = {}
        only_in_new = {}
        changed = {}
        diff.each do |diff_obj|
          (type, title, the_rest) = diff_obj[1].split(/\f/, 3)
          key = "#{type}[#{title}]"
          if ['-', '+'].include?(diff_obj[0])
            only_in_old[key] = { diff: diff_obj[2], loc: diff_obj[3] } if diff_obj[0] == '-'
            only_in_new[key] = { diff: diff_obj[2], loc: diff_obj[3] } if diff_obj[0] == '+'
          elsif ['~', '!'].include?(diff_obj[0])
            # HashDiff reports these as diffs for some reason
            next if diff_obj[2].nil? && diff_obj[3].nil?

            # This turns "foo\fbar\fbaz" into hash['foo']['bar']['baz']
            result = the_rest.split(/\f/).reverse.inject(old: diff_obj[2], new: diff_obj[3]) { |a, e| { e => a } }

            # Assign to appropriate variable
            diff = changed.key?(key) ? changed[key][:diff] : {}
            simple_deep_merge!(diff, result)
            changed[key] = { diff: diff, old_loc: diff_obj[4], new_loc: diff_obj[5] }
          else
            raise "Unrecognized diff symbol '#{diff_obj[0]}' in #{diff_obj.inspect}"
          end
        end
        [only_in_new, only_in_old, changed]
      end

      # Utility Method!
      # Deep merge two hashes. (The 'deep_merge' gem seems to de-duplicate arrays so this is a reinvention
      # of the wheel, but a simpler wheel that does just exactly what we need.)
      # @param hash1 [Hash] First object
      # @param hash2 [Hash] Second object
      def self.simple_deep_merge!(hash1, hash2)
        raise ArgumentError, 'First argument to simple_deep_merge must be a hash' unless hash1.is_a?(Hash)
        raise ArgumentError, 'Second argument to simple_deep_merge must be a hash' unless hash2.is_a?(Hash)
        hash2.each do |k, v|
          if v.is_a?(Hash) && hash1[k].is_a?(Hash)
            # We can only merge a hash with a hash. If hash1[k] is something other than a hash, say for example
            # a string, then the merging is NOT invoked and hash1[k] gets directly overwritten in the `else` clause.
            # Also if hash1[k] is nil, it falls through to the `else` clause where it gets set directly to the result
            # hash without needless iterations.
            simple_deep_merge!(hash1[k], v)
          else
            hash1[k] = v
          end
        end
      end
    end
  end
end