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 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 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
# encoding: UTF-8
# frozen_string_literal: true
require 'stringio'
class Riddle::Configuration::Parser
SOURCE_CLASSES = {
'mysql' => Riddle::Configuration::SQLSource,
'pgsql' => Riddle::Configuration::SQLSource,
'mssql' => Riddle::Configuration::SQLSource,
'xmlpipe' => Riddle::Configuration::XMLSource,
'xmlpipe2' => Riddle::Configuration::XMLSource,
'odbc' => Riddle::Configuration::SQLSource,
'tsvpipe' => Riddle::Configuration::TSVSource
}
INDEX_CLASSES = {
'plain' => Riddle::Configuration::Index,
'distributed' => Riddle::Configuration::DistributedIndex,
'rt' => Riddle::Configuration::RealtimeIndex,
'template' => Riddle::Configuration::TemplateIndex
}
def initialize(input)
@input = input
end
def parse!
set_common
set_indexer
set_searchd
set_sources
set_indices
add_orphan_sources
configuration
end
private
def add_orphan_sources
all_names = sources.keys
attached_names = configuration.indices.collect { |index|
index.respond_to?(:sources) ? index.sources.collect(&:name) : []
}.flatten
(all_names - attached_names).each do |name|
configuration.sources << sources[name]
end
end
def inner
@inner ||= InnerParser.new(@input).parse!
end
def configuration
@configuration ||= Riddle::Configuration.new
end
def sources
@sources ||= {}
end
def each_with_prefix(prefix)
inner.keys.select { |key| key[/^#{prefix}\s+/] }.each do |key|
yield key.gsub(/^#{prefix}\s+/, '').gsub(/\s*\{$/, ''), inner[key]
end
end
def set_common
set_settings configuration.common, inner['common'] || {}
end
def set_indexer
set_settings configuration.indexer, inner['indexer'] || {}
end
def set_searchd
set_settings configuration.searchd, inner['searchd'] || {}
end
def set_sources
each_with_prefix 'source' do |name, settings|
names = name.split(/\s*:\s*/)
types = settings.delete('type')
parent = names.length > 1 ? names.last : nil
types ||= [sources[parent].type] if parent
type = types.first
source = SOURCE_CLASSES[type].new names.first, type
source.parent = parent
set_settings source, settings
sources[source.name] = source
end
end
def set_indices
each_with_prefix 'index' do |name, settings|
names = name.split(/\s*:\s*/)
type = (settings.delete('type') || ['plain']).first
index = INDEX_CLASSES[type].new names.first
index.parent = names.last if names.length > 1
(settings.delete('source') || []).each do |source_name|
index.sources << sources[source_name]
end
set_settings index, settings
configuration.indices << index
end
end
def set_settings(object, hash)
hash.each do |key, values|
values.each do |value|
set_setting object, key, value
end
end
end
def set_setting(object, key, value)
if object.send(key).is_a?(Array)
object.send(key) << value
else
object.send "#{key}=", value
end
end
class InnerParser
SETTING_PATTERN = /^(\w+)\s*=\s*(.*)$/
EndOfFileError = Class.new StandardError
def initialize(input)
@stream = StringIO.new(input.gsub("\\\n", ''))
@sections = {}
end
def parse!
while label = next_line do
@sections[label] = next_settings
end
@sections
rescue EndOfFileError
@sections
end
private
def next_line
line = @stream.gets
raise EndOfFileError if line.nil?
line = line.strip
(line.empty? || line[/^#/]) ? next_line : line
end
def next_settings
settings = Hash.new { |hash, key| hash[key] = [] }
line = ''
while line.empty? || line == '{' do
line = next_line
end
while line != '}' do
begin
match = SETTING_PATTERN.match(line)
unless match.nil?
key, value = *match.captures
settings[key] << value
while value[/\\$/] do
value = next_line
settings[key].last << "\n" << value
end
end
rescue => error
raise error, "Error handling line '#{line}': #{error.message}",
error.backtrace
end
line = next_line
end
settings
end
end
end
|