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 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
|
# encoding: utf-8
require 'stringio'
require_relative '../../hocon/impl'
require_relative '../../hocon/impl/full_includer'
require_relative '../../hocon/impl/url'
require_relative '../../hocon/impl/config_impl'
require_relative '../../hocon/config_error'
require_relative '../../hocon/config_syntax'
require_relative '../../hocon/impl/simple_config_object'
require_relative '../../hocon/impl/simple_config_origin'
require_relative '../../hocon/config_includer_file'
require_relative '../../hocon/config_factory'
require_relative '../../hocon/impl/parseable'
class Hocon::Impl::SimpleIncluder < Hocon::Impl::FullIncluder
ConfigBugorBrokenError = Hocon::ConfigError::ConfigBugOrBrokenError
ConfigIOError = Hocon::ConfigError::ConfigIOError
SimpleConfigObject = Hocon::Impl::SimpleConfigObject
SimpleConfigOrigin = Hocon::Impl::SimpleConfigOrigin
def initialize(fallback)
@fallback = fallback
end
# ConfigIncludeContext does this for us on its options
def self.clear_for_include(options)
# the class loader and includer are inherited, but not this other stuff
options.set_syntax(nil).set_origin_description(nil).set_allow_missing(true)
end
# this is the heuristic includer
def include(context, name)
obj = self.class.include_without_fallback(context, name)
# now use the fallback includer if any and merge its result
if ! (@fallback.nil?)
obj.with_fallback(@fallback.include(context, name))
else
obj
end
end
# the heuristic includer in static form
def self.include_without_fallback(context, name)
# the heuristic is valid URL then URL, else relative to including file;
# relativeTo in a file falls back to classpath inside relativeTo().
url = nil
begin
url = Hocon::Impl::Url.new(name)
rescue Hocon::Impl::Url::MalformedUrlError => e
url = nil
end
if !(url.nil?)
include_url_without_fallback(context, url)
else
source = RelativeNameSource.new(context)
from_basename(source, name, context.parse_options)
end
end
# NOTE: not porting `include_url` or `include_url_without_fallback` from upstream,
# because we probably won't support URL includes for now.
def include_file(context, file)
obj = self.class.include_file_without_fallback(context, file)
# now use the fallback includer if any and merge its result
if (!@fallback.nil?) && @fallback.is_a?(Hocon::ConfigIncluderFile)
obj.with_fallback(@fallback).include_file(context, file)
else
obj
end
end
def self.include_file_without_fallback(context, file)
Hocon::ConfigFactory.parse_file_any_syntax(file, context.parse_options).root
end
# NOTE: not porting `include_resources` or `include_resources_without_fallback`
# for now because we're not going to support looking for things on the ruby
# load path for now.
def with_fallback(fallback)
if self.equal?(fallback)
raise ConfigBugOrBrokenError, "trying to create includer cycle"
elsif @fallback.equal?(fallback)
self
elsif @fallback.nil?
self.class.new(@fallback.with_fallback(fallback))
else
self.class.new(fallback)
end
end
class NameSource
def name_to_parseable(name, parse_options)
raise Hocon::ConfigError::ConfigBugOrBrokenError,
"name_to_parseable must be implemented by subclass (#{self.class})"
end
end
class RelativeNameSource < NameSource
def initialize(context)
@context = context
end
def name_to_parseable(name, options)
p = @context.relative_to(name)
if p.nil?
# avoid returning nil
Hocon::Impl::Parseable.new_not_found(name, "include was not found: '#{name}'", options)
else
p
end
end
end
# this function is a little tricky because there are three places we're
# trying to use it; for 'include "basename"' in a .conf file, for
# loading app.{conf,json,properties} from classpath, and for
# loading app.{conf,json,properties} from the filesystem.
def self.from_basename(source, name, options)
obj = nil
if name.end_with?(".conf") || name.end_with?(".json") || name.end_with?(".properties")
p = source.name_to_parseable(name, options)
obj = p.parse(p.options.set_allow_missing(options.allow_missing?))
else
conf_handle = source.name_to_parseable(name + ".conf", options)
json_handle = source.name_to_parseable(name + ".json", options)
got_something = false
fails = []
syntax = options.syntax
obj = SimpleConfigObject.empty(SimpleConfigOrigin.new_simple(name))
if syntax.nil? || (syntax == Hocon::ConfigSyntax::CONF)
begin
obj = conf_handle.parse(conf_handle.options.set_allow_missing(false).
set_syntax(Hocon::ConfigSyntax::CONF))
got_something = true
rescue ConfigIOError => e
fails << e
end
end
if syntax.nil? || (syntax == Hocon::ConfigSyntax::JSON)
begin
parsed = json_handle.parse(json_handle.options.set_allow_missing(false).
set_syntax(Hocon::ConfigSyntax::JSON))
obj = obj.with_fallback(parsed)
got_something = true
rescue ConfigIOError => e
fails << e
end
end
# NOTE: skipping the upstream block here that would attempt to parse
# a java properties file.
if (! options.allow_missing?) && (! got_something)
if Hocon::Impl::ConfigImpl.trace_loads_enabled
# the individual exceptions should have been logged already
# with tracing enabled
Hocon::Impl::ConfigImpl.trace("Did not find '#{name}'" +
" with any extension (.conf, .json, .properties); " +
"exceptions should have been logged above.")
end
if fails.empty?
# this should not happen
raise ConfigBugOrBrokenError, "should not be reached: nothing found but no exceptions thrown"
else
sb = StringIO.new
fails.each do |t|
sb << t
sb << ", "
end
raise ConfigIOError.new(SimpleConfigOrigin.new_simple(name), sb.string, fails[0])
end
elsif !got_something
if Hocon::Impl::ConfigImpl.trace_loads_enabled
Hocon::Impl::ConfigImpl.trace("Did not find '#{name}'" +
" with any extension (.conf, .json, .properties); but '#{name}'" +
" is allowed to be missing. Exceptions from load attempts should have been logged above.")
end
end
end
obj
end
class Proxy < Hocon::Impl::FullIncluder
def initialize(delegate)
@delegate = delegate
end
## TODO: port remaining implementation when needed
end
def self.make_full(includer)
if includer.is_a?(Hocon::Impl::FullIncluder)
includer
else
Proxy.new(includer)
end
end
end
|