ext/facter/facter/lib/src/ruby/fact.cc in facter-3.12.1.cfacter.20181031 vs ext/facter/facter/lib/src/ruby/fact.cc in facter-3.12.2.cfacter.20181217

- old
+ new

@@ -81,56 +81,72 @@ auto res_second = ruby.to_native<resolution>(second); return res_first->weight() > res_second->weight(); }); _resolving = true; - - // If no resolutions or the top resolution has a weight of 0, first check the native collection for the fact - // This way we treat the "built-in" as implicitly having a resolution with weight 0 bool add = true; - if (_resolutions.empty() || ruby.to_native<resolution>(_resolutions.front())->weight() == 0) { - // Check to see the value is in the collection - auto value = facts[ruby.to_string(_name)]; - if (value) { - // Already in collection, do not add - add = false; - _value = facter->to_ruby(value); - _weight = value->weight(); - } - } - if (ruby.is_nil(_value)) { - vector<VALUE>::iterator it; - ruby.rescue([&]() { - volatile VALUE value = ruby.nil_value(); - size_t weight = 0; + vector<VALUE>::iterator it; + ruby.rescue([&]() { + volatile VALUE value = ruby.nil_value(); + size_t weight = 0; - // Look through the resolutions and find the first allowed resolution that resolves - for (it = _resolutions.begin(); it != _resolutions.end(); ++it) { - auto res = ruby.to_native<resolution>(*it); - if (!res->suitable(*facter)) { - continue; - } - value = res->value(); - if (!ruby.is_nil(value)) { - weight = res->weight(); - break; - } + // Look through the resolutions and find the first allowed resolution that resolves + for (it = _resolutions.begin(); it != _resolutions.end(); ++it) { + auto res = ruby.to_native<resolution>(*it); + if (!res->suitable(*facter)) { + continue; } + value = res->value(); + if (!ruby.is_nil(value)) { + weight = res->weight(); + break; + } + } - // Set the value to what was resolved - _value = value; - _weight = weight; - return 0; - }, [&](VALUE ex) { - LOG_ERROR("error while resolving custom fact \"{1}\": {2}", ruby.rb_string_value_ptr(&_name), ruby.exception_to_string(ex)); + // Set the value to what was resolved + _value = value; + _weight = weight; - // Failed, so set to nil - _value = ruby.nil_value(); - _weight = 0; + if (! ruby.is_nil(_value) && _weight != 0) { return 0; - }); - } + } + + // There's two possibilities here: + // 1. None of our resolvers could resolve the value + // 2. A resolver of weight 0 resolved the value + // + // In both cases, we attempt to use the "built-in" fact's + // value. This serves as a fallback resolver for Case (1) + // while for Case (2), we want built-in values to take + // precedence over 0-weight custom facts. + + auto builtin_value = facts[ruby.to_string(_name)]; + if (! builtin_value) { + return 0; + } + auto builtin_ruby_value = facter->to_ruby(builtin_value); + + // We need this check for Case (2). Otherwise, we risk + // overwriting our resolved value in the small chance + // that builtin_value exists, but its ruby value is + // nil. + if (! ruby.is_nil(builtin_ruby_value)) { + // Already in collection, do not add + add = false; + _value = builtin_ruby_value; + _weight = builtin_value->weight(); + } + + return 0; + }, [&](VALUE ex) { + LOG_ERROR("error while resolving custom fact \"{1}\": {2}", ruby.rb_string_value_ptr(&_name), ruby.exception_to_string(ex)); + + // Failed, so set to nil + _value = ruby.nil_value(); + _weight = 0; + return 0; + }); if (add) { facts.add_custom(ruby.to_string(_name), ruby.is_nil(_value) ? nullptr : make_value<ruby::ruby_value>(_value), _weight); }