Class: App::Replacer
- Inherits:
-
Object
- Object
- App::Replacer
- Defined in:
- lib/core/replacer.rb
Constant Summary collapse
- REGEXP_MATCHER =
/\$\{\{[^}]+\}\}/
- REGEXP_MULTILINE =
/^[A-Za-z0-9]+:\s*\|$/
- REGEXP_MODIFIER =
/^\$\{\{awx-(for|end).*\}\}$/
- TYPE_YML =
'yml'
- VALID_MODIFIERS =
%w(base64encode)
- OP_SCAN =
'scan'
- OP_REPLACE =
'replace'
- SSH_USERS =
'SSHUsers'
Class Method Summary collapse
-
.replace_string(line, data) ⇒ Object
Takes a string, replaces all the matchers and returns string.
-
.replace_yml(path_and_file, data) ⇒ Object
Takes file path and returns array of lines (that can then be used to write same/new file).
-
.scan_file(path_and_file, operation = OP_SCAN, data: nil, new_lines: nil) ⇒ Object
Return Array of Hashes containing all matchers.
-
.scan_string(line) ⇒ Object
Return Array of Hashes containing all matchers.
Class Method Details
.replace_string(line, data) ⇒ Object
Takes a string, replaces all the matchers and returns string.
170 171 172 173 174 175 176 |
# File 'lib/core/replacer.rb', line 170 def self.replace_string(line, data) return nil if line.nil? raise RuntimeError, "Expected String, instead got #{line.class}" unless line.is_a?(String) raise RuntimeError, "Expected Hash, instead got #{data.class}" unless data.is_a?(Hash) line, x, y = process_matchers(line, {}, [], OP_REPLACE, data: data) return line end |
.replace_yml(path_and_file, data) ⇒ Object
Takes file path and returns array of lines (that can then be used to write same/new file).
180 181 182 183 184 185 186 187 188 189 |
# File 'lib/core/replacer.rb', line 180 def self.replace_yml(path_and_file, data) raise RuntimeError, "Expected String, instead got #{path_and_file.class}" unless path_and_file.is_a?(String) raise RuntimeError, "Expected Hash, instead got #{data.class}" unless data.is_a?(Hash) extension = Blufin::Files::extract_file_name(path_and_file).split('.') extension = extension[extension.length - 1].downcase raise RuntimeError, "Expected YML file, instead got: #{path_and_file}" unless %w(yml yaml).include?(extension) new_lines = [] scan_file(path_and_file, OP_REPLACE, data: data, new_lines: new_lines) new_lines end |
.scan_file(path_and_file, operation = OP_SCAN, data: nil, new_lines: nil) ⇒ Object
Return Array of Hashes containing all matchers. Use this for validation.
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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/core/replacer.rb', line 30 def self.scan_file(path_and_file, operation = OP_SCAN, data: nil, new_lines: nil) raise RuntimeError, "File does not exist: #{path_and_file}" unless Blufin::Files::file_exists(path_and_file) raise RuntimeError, "Cannot call scan_file without new_lines being an Array when operation is #{OP_REPLACE}." if operation == OP_REPLACE && !new_lines.is_a?(Array) matchers = {} errors = [] multiline = nil awx_for = nil line_count = 0 Blufin::Files::read_file(path_and_file).each do |line| next if line =~ /^\s*#/ && line !~ /^\s*#cloud-config/ # Skip comments (but not #cloud-config). line = line.gsub("\n", '') line_count += 1 # This handles multi-line block (IE -> content: | ) which basically gets skipped. # If you want to make replace work within comments, you will need to write more code (or possibly just add a flag?). if line.strip =~ REGEXP_MULTILINE # Stores the number of spaces from start. multiline = line[/\A */].size awx_for[:lines] << line if awx_for.is_a?(Hash) new_lines << line if operation == OP_REPLACE && awx_for.nil? next elsif !multiline.nil? whitespace_from_start = line[/\A */].size # If white-space from beginning is same or higher, we're probably still in a multi-line. if line.strip == '' || whitespace_from_start > multiline awx_for[:lines] << line if awx_for.is_a?(Hash) new_lines << line if operation == OP_REPLACE && awx_for.nil? next end # Otherwise, break-out. multiline = nil end # This handles ${{awx-[modifier]}} tags. if line.strip =~ REGEXP_MODIFIER awx_modifier = line.strip.gsub(/^\$\{\{awx-/, '').gsub(/\}\}$/, '') # Handle end-tag first. if awx_modifier == 'end' if awx_for.is_a?(Hash) if operation == OP_SCAN # Handle matchers. if awx_for[:matchers].any? awx_for[:matchers].each do |k, v| if k != awx_for[:item] matchers[k] = [] unless matchers.has_key?(k) matchers[k].push(*v) end end end # Handle errors. errors.push(*awx_for[:errors]) if awx_for[:errors].any? else ms = awx_for[:item_source].split(':') raise RuntimeError, "Invalid key: #{ms[0]}" unless data.has_key?(ms[0]) raise RuntimeError, "Invalid key: #{ms[0]}.#{ms[1]}" unless data[ms[0]].has_key?(ms[1]) is = data[ms[0]][ms[1]] awx_for_data = data if is.is_a?(Array) if ms[1] == SSH_USERS # SSH Users get handled differently. is.each do |ssh_key_file| raise RuntimeError, "File not found: #{ssh_key_file}" unless Blufin::Files::file_exists(ssh_key_file) contents = [] Blufin::Files::read_file(ssh_key_file).each do |c| next if c.strip == '' contents << c end awx_for_data[awx_for[:item]] = { 'name' => Blufin::Files::extract_file_name(ssh_key_file).gsub(/\.pub$/i, '').gsub(/\./, '-'), 'pub_key' => contents.join("\n") } new_lines = process_awx_for_loop(awx_for, awx_for_data, new_lines) end else # TODO - Finish this. raise RuntimeError, 'Not yet implemented!' end else # TODO - Finish this. raise RuntimeError, 'Not yet implemented!' end end awx_for = nil end next end # If a tag is already open, return an error (or throw one). unless awx_for.nil? tag_open_error = "Detected #{line.strip} tag even though another one is already open (Line: #{line_count})." if operation == OP_SCAN errors << tag_open_error next else raise RuntimeError, tag_open_error end end # Hits here at the start of a for loop (IE: ${{awx-for(user in Parameters:SSHUsers)}}) if awx_modifier =~ /for\([A-Za-z0-9]+\s*in\s*[A-Za-z0-9]+:[A-Za-z0-9]+\)/ ams = awx_modifier.strip.gsub(/^for\(/, '').gsub(/\)$/, '') ams = ams.split(' ') awx_for = { :lines => [], :item => ams[0], :item_source => ams[2], :matchers => {}, :errors => [] } line, matchers, errors = process_matchers("${{#{ams[2]}}}", matchers, errors, OP_SCAN, data: data, file: path_and_file) next else raise RuntimeError, "Unsupported awx modifier: #{awx_modifier}" end end # If we're in a for loop, start buffering content. if awx_for.is_a?(Hash) if operation == OP_SCAN line, awx_for[:matchers], awx_for[:errors] = process_matchers(line, awx_for[:matchers], awx_for[:errors], operation, data: data, file: path_and_file) end awx_for[:lines] << line next end # This just processes a regular line. line, matchers, errors = process_matchers(line, matchers, errors, operation, data: data, file: path_and_file) if line =~ REGEXP_MATCHER new_lines << line if operation == OP_REPLACE end if operation == OP_SCAN return { :matchers => matchers, :errors => errors } else return new_lines end end |
.scan_string(line) ⇒ Object
Return Array of Hashes containing all matchers. Use this for validation.
17 18 19 20 21 22 23 24 25 |
# File 'lib/core/replacer.rb', line 17 def self.scan_string(line) matchers = {} errors = [] x, matchers, errors = process_matchers(line, matchers, errors, OP_SCAN) if line =~ REGEXP_MATCHER return { :matchers => matchers, :errors => errors } end |